来杯JAVA冷静一下_05面向对象_06异常_230809
# 来杯JAVA冷静一下_05面向对象_06异常_230809











面向对象
### 1.初识面向对象
#### 面向过程思想
步骤清晰简单,第一步做什么,第二步做什么…
面对过程适合处理一些较为简单的问题。
#### 面向对象思想
物以类聚,分类的思维模式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索。
面向对象适合处理复杂的问题,适合处理需要多人协作的问题!
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象的思路来分析整个系统。但是,具体到微观操作,仍然需要面向过程的思路去处理。
面向对象编程( Object- Oriented Programming,OOP)
### 面向对象编程的本质就是:
### -以类的方式组织代码,
### -以对象的组织(封装)数据。
#### 三大特征:
##### 继承
##### 封装
##### 多态
- 从认识论角度考虑是先有对象后有类。对象,是具体的事物。
- 类,是抽象的,是对对象的抽象。
- 从代码运行角度考虑是先有类后有对象。类是对象的模板。
-
### 2.方法回顾和加深 属性+方法=类
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,我们需要使用面向对象来分析整个系统。但是,具体到微观操作,让然需要面向过程的思路去处理。
面向对象本质就是:以类的方式组织代码,以对象的组织(封装)数据。
从认识论角度考虑是先有对象后有类
三大特性:封装,继承,多态。抽象
回顾方法的定义以及调用
定义
main方法
#### 1 方法的定义
1. 修饰符 public 公共类 private 私有类
2. 返回值类型
break:跳出 switch,结束循环和 return的区别。
3. 方法名:注意规范就OK,见名知意
参数列表:(参数类型,参数名) …
异常抛出:疑问,参考下文!
```java
//main方法
public static void main(String[] args){}
/*
修饰符 返回值类型 方法名(...){
//方法体
return 返回值;
}
*/
public String sayHello(){
return "hello world";
}
public void print(){
return;
}
public int max(int a,int b){
return a>b ?a:b;
}
```
break:跳出switch循环,结束循环。continue:结束依次循环。return:方法结束,返回类型和返回值相同。
```java
public class Demo01 {
// main方法
public static void main(String[] args) {
}
/*
修饰符 返回值类型 方法名(...){
// 方法体
return 返回值;
}
*/
public String sayHello(){
return "hello,world!";
}
public int max(int a,int b){
return a>b ? a : b; // 三元运算符
}
// 数组下标越界:Arrayindexoutofbounds
public void readFile(String file) throws IOException{
}
}
```
### 3 方法的调用
#### 1 静态方法
public static void a(){
b}//和类一起加载的
```java
public class Demo01 {
public static void main(String[] args) {
Student.main();
}
}
//==============另一个文件
//1 静态方法
public class Student {
public static void main() {
System.out.println("学生说话。。。");
}
}
```
#### 2 非静态方法
public void b() {
}
//类实例化之后才存在
```java
public class Student {
public void main() {//去掉static
System.out.println("学生hh说话。。。");
}
}
//=======================
public class Demo01 {
public static void main(String[] args) {
// Student.main();
// 去掉static后 无法直接通过类名调用方法名
//只能通过实例化
Student studnet = new Student();
studnet.main();
}
}
```
#### 3 形参和实参
```java
public static void say(){
system.out.print("1111");
}//可直接通过方法名调用,和类一起加载。
非静态方法
public void say(){
System.out.print("1111");
}
//调用
Student student = new Student();//实例化这个类new,对象类型 对象名=对象值;
student.say();
形参
public static int add(int a,int b){//int a,int b,形参
return a+b;
}
实参
public static void main(String[] args){
int add = Demo03.add(1,3);//1,3:实参
System.out.println(add);
}
```
#### 4 java 都是值传递
一句话:对于**基本数据类型**来说,给形参传递的是实参值的副本,而对于引用数据类型来说,传递的则是地址的副本。但由于地址的副本和原来的相似,因此传递过去后的形参也指向同一个内存空间中。
就是复制了一份给形参,自身不变
形参的有效范围只在当前方法内,输出的值跟下面的a完全没有任何关系
```java
//值传递
public class Demo04{
public static void main(String[] args){
int a=1;
System.out.println(a);
Demo04.change(a); //返回值为空 运行完,啥也没有
System.out.println(a);
}
//返回值为空 运行完,啥也没有
public static void change(int a){//a传进去1
a=10;//a= 1 ,将10 赋值给a,a=10;
}
}
a=10,返回值为空,a的值还为1。
```
#### 5 引用传递
```java
//引用传递:对象,本质还是值传递
public class Demo05{
public static void main(String[] args){
Person person = new Person();
System.out.println(person.name);//null
Demo05.change(person);
System.out.println(person,name);//test
}
public static void change(Person person){
//person是一个对象:指向的--->Person person=new Person();这是一个具体的人,可以改变属性
person.name = "test";
};
}
//定义了一个Person类,有一个属性:name
class Person{
String name;//null
}
```
- 基本类型作为参数传递时,是传递值的拷贝,无论你怎么改变这个拷贝,原值是不会改变的
- 对象作为参数传递时,是对象在内存中的地址拷贝一份给了参数
类和对象的关系
类是一种抽向的数据类型,它是对某一类事物整体描述/定义,但是并不能代表某一个具体的事物
对象是抽象概念的具体实例
#### 6 this关键字
#### 学程序好? 对世界进行更好的建模
### 4 类和对象的创建
对象的创建分析
类是一种抽象的数据类型它是对某一类事物整体描述/定义但是并不能代表某一个具体的事物。
使用new关键字创建对象。
使用new关键字创建的时候,除了分配内存空间之外,还会给刨建好的对象进行默认的初始化以及对类中构造器的调用。
#### 创建和初始化对象
使用new关键字创建的时候,除了分配内存空间之外,还会给创建好的对象进行默认的初始化以及类中构造器的使用
1595485938430
一个类即使什么都不写,它也会存在一个方法
```java
//学生类 以类的方式组织代码
public class Student {
//1 属性 :字段 不赋值 。
String name;
int age;
//2 方法
public void study() {
System.out.println(
this.name + "在学习"
);
}
}
```
```java
package com.zhangyy.opp;
//引用传递:对象,本质还是值传递
public class Demo05 {
public static void main(String[] args) {
//类:抽象的 示例化
//类:抽象的,实例化
// 类实例化后会返回一个自己的对象!
// student对象就是一个student类的具体实例!
Student xiaoming=new Student();
Student xh =new Student();
xiaoming.name = "小明";
xiaoming.age=23;
System.out.println(xiaoming.name);
System.out.println(xiaoming.age);
System.out.println(xh.name);
System.out.println(xh.age);
}
;
}
/*
小明
23
null
0
*/
```
```java
//引用传递:对象,本质还是值传递
public class Demo05 {
public static void main(String[] args) {
//类:抽象的 示例化
//类:抽象的,实例化
// 类实例化后会返回一个自己的对象!
// student对象就是一个student类的具体实例!
Student xiaoming=new Student();
Student xh =new Student();
xiaoming.name = "小明";
xiaoming.age=18;
System.out.println(xiaoming.name);
System.out.println(xiaoming.age);
System.out.println(xh.name);
System.out.println(xh.age);
}
;
}
```
### 5 构造器
#### 构造器:
```java
//Person.class
public class Person {
}
```
#### Person.class默认无参构造方法
```java
//Person.class默认 无参构造 方法
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.zhangyy.opp;
public class Person {
public Person() {
}
}
```
#### 类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。
#### 并且构造器有以下俩个特点:
//一个类即使什么都不写,它也会存在一个方法
//显示的定义构造器
##### 1.必须和类的名字相同;
##### 2.必须没有返回类型也不能写void。
#### 构造器: Command + N 方法的重载
快捷键 Command + N 打开Generate 操作菜单; 选择Constructor,然后根据需要选择相应的构造函数参数; 点击OK,即可生成相应的构造函数。
##### 1.和类名相同
##### 2.没有返回值类型,也不能写void
#### 作用:
##### 1.new本质在调用构造方法,默认无参构造方法;
##### 2.初始化对象的值。
#### 有参构造与无参构造
#### 注意:定义有参构造之后,如果想使用无参构造,显示的定义一个无参构造。
构造器是无参构造,方法也可以无参构造
显示定义无藏构造:
//定义有参构造器后,就会把系统默认的无参构造器给覆盖掉了。如果想使用无参构造器,那就得自己写出来,即显示的定义无参构造器。
定义有参构造器,它会覆盖无参构造器,如果你想要它还存在,那么就自己定义出来。
方法重载:有参无参都写上,有参数就走有参,无参数就走无参,出来的是定义 的值

```java
public class Person {
String name;
// public Person(){
//
// this.name="雪之下雪乃";
// }
public Person( String name){
this.name = name;
}
}
```
```java
public class Demo01 {
public static void main(String[] args) {
Person person = new Person("雪之下");
System.out.println(person.name);
}
}
//雪之下
```
#### A 未使用构造器
```java
public class Person {
String name;
}
```
```java
public class Demo01 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
}
}
//null
```
#### B 使用构造器
//一个类即使什么都不写,它也会存在一个方法
//显示的定义构造器
//实例化初始值
//1。使new关键字,本质是在调用构造器
```java
public class Person {
String name;
public Person(){
this.name="雪之下雪乃";
}
```
```java
public class Demo01 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
}
}
//雪之下雪乃
```

### 6 内存分析


没有static时,b调用的是对象的方法,而b是用A类new的,即b是A new出来的对象,因此调用了A的方法
### 7 小结类与对象
#### 1.类与对象
###### 类是一个模板:抽象,对象是一个具体的实例
#### 2.方法
###### 定义,通用
#### 3.对应的引用
###### 引用类型:基本类型(8)
###### 对象是通过引用来操作的:栈--->堆(地址)
#### 4.属性:字段Field 成员变量
###### 默认初始化:
###### 数字:0 0.0
###### char:u0000
###### boolean:false
###### 引用类型(String等):null
###### 修饰符 属性类型 属性名=属性值;
(方法省略 不要死循环)
#### 5.对象的创建和使用
- 必须使用new关键字创建对象, 构造器Person xiaoming=new Perosn();
- 对象的属性 xiaoming.name
- 对象的方法 xiaoming.sleep()
#### 6.类
###### 静态的属性 属性
###### 动态的行为 方法
***
***
***
> # 面向对象三大特性:封装 继承 多态
### 8 封装 属性私有,get/set 高内聚低耦合
**主要是针对类的属性进行封装**
该露的露,该藏的藏 类比ATM机
我们程序设计要追求**”高内聚,低耦合“**。高内聚就是类的内部数据细节由自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用。
#### 封装(数据的隐藏)
通常,应禁止直接访问一个对象中数据的实际表示,而应该通过操作接口来访问,称为信息隐藏。
#### 属性私有,get/set
快捷键 Command + N = Mac中对应的是:control+enter
可以在get方法里面对传入的数据做合法性判断
这就相当于银行取钱,我能看见余额,但不能修改余额
因为你是private的所以要设置getter和setter, 如果不需要更改就不用设置, public安全程度低
示例1:
```java
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Person() {
}
public Person(String name) {
this.name = name;
}
}
```
示例2:
```java
public class Student{
//名字
private String name;
//学号
private int id;
//性别
private char sex;
//年龄
private int age;
public int getAge(){
if(age>120 || age<0){
this.age=3;
}else{
this.age=age;
}
return age;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
this.name=name;
}
public void setName(String name){
this.name=name;
}
public int getId(){
return id;
}
public void setId(int id){
this.id=id;
}
public char getSex(){
return sex;
}
public void setSex(char sex){
this.sex=sex;
}
}
//==========
public class a{
{
psvm{
Students s1=new Students();
s1.setAge(1200);
System.out.println(s1.getAge());}
}
}
```
#### 作用
###### 1. 提高程序的安全性,保护数据
###### 2. 隐藏代码的实现细节
###### 3. 统一接口
###### 4. 系统可维护性增加了
### 9 继承
#### 类 = 属性 + 方法
但是 鸟类 鱼类 虫类 猴类。。。
类太多了 也要进行抽象
1. 继承的本质是对某一批类的抽象,从而实现对世界更好的建模
2. extends的意思是“扩展”。子类是父类的扩展,使用extends来表示
3. Java中只有单继承,没有多继承!一个类只能继承一个父类
4. 继承是类与类之间的一种关系,此外还有依赖、组合、聚合等
5. 继承关系的两个类,一个是子类(派生类),一个是父类(基类)子类继承父类
6. 子类继承了父类,就会拥有父类的全部方法,而private私有属性及方法无法继承
7. 在Java中,所有类,都默认直接或间接继承Object类(Ctrl+H可以查看类关系)
8. 被final修饰的类,无法继承(断子绝孙)
### 10 super&this
#### super注意点:
###### 1.super调用父类的构造方法,必须在构造方法的第一个(默认调用)
###### 2.super必须只能出现在子类的方法或者构造方法中
###### 3.super和this不能同时调用构造方法
#### VS this
###### 代表的对象不同:
###### this:本身调用者这个对象
###### super:代表父类对象的应用
###### 前提
###### this:没有继承也可以使用
###### super:只能在继承条件下可以使用
###### 构造方法
###### this():本类的构造
###### super():父类的构造
super与this的区别:super代表父类对象的引用,只能在继承条件下使用;this调用自身对象,没有继承也可以使用
super(); //隐藏代码,默认调用了父类的无参构造,要写只能写第一行

### 11 方法的重写
#### 重写:需要有继承关系,子类重写父类的方法!方法名必须相同
#### 参数列表必须相同
#### 修饰符可以扩大但是不可以缩小
#### public>protected>default>private
#### 抛出的异常:范围,可以被缩小,但是不能扩大:ClassNotFoundException-->Exception(大)
#### 重写是方法的重写,与属性无关
#### 重写方法只与非静态方法有关,与静态方法无关(静态方法不能被重写)
#### 被static(属于类,不属于实例),final(常量方法),private(私有)修饰的方法不能重写


```java
public class B{
public static void test(){静态方法
System.out.println("B==>test()")
}
}
public class A extends B{//继承
public static void test(){
System.out.println("A==>test()")
}
}
public class Application(){
public static void main(String[] args){
//方法的调用只和左边的定义的类型有关
A a = new A();
a.test();//打印A==>test()
//父类的引用指向了子类,但静态方法没有被重写
B b = new A();
b.test();//打印B==>test()
}
}
修改A.Java,B.java
public class B{
public void test(){//非静态方法
System.out.println("B==>test()");
}
}
public class A extends B{
@Override //重写了B的方法
public void test(){
System.out.println("A==>test()");
}
}
//父类的引用指向了子类
B b = new A();
//子类重写了父类的方法,执行子类的方法
b.test();//打印变成了A==>test()
/*
静态方法是类的方法,非静态方法是对象的方法。有static时,b调用了B类的方法,因为b是B类定义的。没有static时,b调用的是对象的方法,而b是A类new出来的对象,调用A的方法
*/
```
重写:子类的方法名必须和父类保持一致,方法体不同
被static(属于类,不属于实例),final(常量方法),private(私有)修饰的方法不能重写
#### 为什么重写:
父类的功能,子类不一定需要,或者不一定满足
Alt + Insert ; override;
### 12 多态
即同一方法可以根据发送对象的不同而采用不同的行为方式
一个对象的实际类型是确定的,但可以指向对象的引用可以有很多
#### 多态存在条件
有继承关系
子类重写父类的方法
父类引用指向子类对象
#### 注意点
多态是方法的多态,没有属性的多态
父类和子类,有联系 类型转换溢出:ClassCastException
存在条件:继承关系,方法需要重写,父类引用指向了子类对象
instanceof和类型转换
instanceof引用类型比较,判断一个对象是什么类型
```java
private static int age;
private double score;
public void run(){ }
public static void go(){ }
public static void main(String[] args){
Student s1 = new Student();
System.out.println(Student.age);
System.out.println(Student.score);
System.out.println(s1.ahe);
System.out.println(s1.score);
go();
run();
}
```
#### 多态的内存分析

#### -编译看左 运行看右 调,但具体调子类的方法 父.方法();//输出son。
编译看左,运行看右” 是指在面向对象编程中,Java编译器在编译时会根据引用变量的类型(左边)来确定可以调用哪些方法和属性,
而在运行时则会根据实际对象的类型(右边)来决定执行哪个方法。这涉及到多态性的概念。
让我用一个例子来解释这个概念:
假设有一个类 Animal 和一个继承自 Animal 的类 Dog:
```java
class Animal {
public void makeSound() {
System.out.println("动物发出声音");
}
}
class Dog extends Animal {
public void makeSound() {
System.out.println("汪汪汪!");
}
}
```
```java
Animal myAnimal = new Dog();
myAnimal.makeSound(); // 输出:"汪汪汪!"
```
**在这里,myAnimal 是一个 Animal 类型的引用,但是它实际指向了 Dog 类的一个实例。**
在编译时,编译器看到 myAnimal 是 Animal 类型,所以它知道可以调用 makeSound 方法。
但是在运行时,因为 myAnimal 实际上指向 Dog 类的实例,所以**会调用 Dog 类的 makeSound 方法**,从而输出 "汪汪汪!"。
这就是“编译看左,运行看右”这个概念的含义。在编译时,编译器会根据左边的类型来确定可用的方法和属性,但在运行时,实际上会根据右边的实际对象来执行相应的方法。

### 13 instanceof (类型转换)引用类型
1. 能否编译通过,看类是否有关系,x与y的类(实际x,y本身就是类)
2. 若存在父子或子父关系责可编译
3. 编译过后T/F 看引用指向对象: 引用变量名x指向的对象 如果是后面y的子类的实例化,即是T。
说到底,就是比较左边的物件 右边的大容器能不能装得下
instanceof 是 Java 中的一个关键字,用于检查一个对象是否是某个类的**实例,或者是否实现了某个接口**。它返回一个布尔值,如果对象是指定类或接口的实例,则返回 true,否则返回 false。
instanceof 主要用于实现多态性中的类型检查,让我们来看一个例子:
```java
class Animal {
}
class Dog extends Animal {
}
class Cat extends Animal {
}
```
##### 使用 instanceof 来检查一个对象是否是某个类的实例:
```java
Animal animal = new Dog();
if (animal instanceof Dog) {
System.out.println("这是一只狗!");
} else if (animal instanceof Cat) {
System.out.println("这是一只猫!");
} else {
System.out.println("这是一只动物!");
}
```
在这个例子中,animal 是一个 Animal 类型的引用,但它实际指向了 Dog 类的一个实例。通过使用 instanceof,我们可以判断实际对象的类型,然后输出相应的信息。
#### instanceof 关键字主要作用和意义:
1. 类型检查和多态性: 一个程序中可能会有许多不同的类和对象,而这些类可能存在继承关系。通过使用 instanceof,可以在运行时确定对象的实际类型,从而进行相应的操作。这在实现多态性时非常有用,让不同的对象以一种统一的方式被处理。
2. 避免类型转换错误: 在使用继承和多态性的情况下,如果尝试将一个对象转换为错误的类型,会导致运行时的异常。使用 instanceof 可以在进行类型转换之前先检查对象的类型,从而避免此类错误。
3. 动态适应性: instanceof 允许程序在运行时根据对象的实际类型做出决策。这种动态适应性使得程序可以根据不同情况做出不同的处理,从而提高了代码的灵活性和可维护性。
4. 接口和抽象类判断: 除了用于类的判断外,instanceof 也可以用于判断一个对象是否实现了某个接口或是抽象类的子类。
5. 安全的类型转换: 在使用类型转换之前使用 instanceof 进行检查,可
以避免不安全的类型转换,从而减少潜在的运行时错误。
总的来说,instanceof 关键字帮助你处理继承和多态性的情况,确保你在操作对象时能够正确地处理不同的对象类型,从而增强代码的稳定性和可读性。它是面向对象编程中一个重要的工具,帮助你更好地利用Java的特性。
#### 类型转换
在Java中,子类和父类之间可以进行类型转换,但需要注意一些规则和限制。类型转换可以分为向上转型(Upcasting)和向下转型(Downcasting)两种情况。
##### 1. 向上转型(Upcasting):
向上转型是指将一个子类对象赋值给父类引用变量,这是安全的,因为子类是父类的特化。在向上转型时,你可以调用父类中定义的方法,但不能调用子类中特有的方法。
示例:
```java
class Animal {
void sound() {
System.out.println("动物发出声音");
}
}
class Dog extends Animal {
void sound() {
System.out.println("汪汪汪!");
}
void fetch() {
System.out.println("狗会接东西");
}
}
//编译看左 运行看右
public class Main {
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型
animal.sound(); // 调用的是 Dog 类中的 sound 方法 汪汪汪
// animal.fetch(); // 错误!Animal 类没有 fetch 方法
}
}
```
##### 2. 向下转型(Downcasting):
向下转型是指将一个父类引用变量转换为子类引用变量,但这需要在编译时和运行时都要进行**安全检查**。只有在父类引用实际上指向一个**子类对象**时,向下转型才会成功。如果转型失败,会抛出 ClassCastException 异常。
示例:
```java
class Animal {
void sound() {
System.out.println("动物发出声音");
}
}
class Dog extends Animal {
void sound() {
System.out.println("汪汪汪!");
}
void fetch() {
System.out.println("狗会接东西");
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Dog(); // 向上转型
if (animal instanceof Dog) {
Dog myDog = (Dog) animal; // 向下转型
myDog.sound(); // 调用 Dog 类中的 sound 方法
myDog.fetch(); // 调用 Dog 类中的 fetch 方法
} else {
System.out.println("对象不是 Dog 类的实例");
}
}
}
```
##### instanceof在类型转换中的作用
因此,需要注意的是,向下转型时需要使用 (子类类型) 进行显式的类型转换,并且最好在转型前使用 **instanceof **来进行类型检查,以避免可能的异常。
父类型引用指向子类型对象,需要调用子类所特有的方法时,需要强制类型转换
父类是高类型,子类是低类型;低转高,自动转换;高转低,要舍弃。所以强制剥夺转换
#### 子类和父类之间的类型转换在Java中有其优点和缺点:
#### 优点:
###### 代码灵活性:
类型转换允许你在不同的情境下使用相同的代码处理不同类型的对象。这在实现多态性和通用代码时非常有用,使得代码更具灵活性和可重用性。
###### 动态适应性:
类型转换允许你在运行时根据实际对象的类型做出决策。这在根据不同的条件采取不同的操作时很有用,增加了程序的动态适应性。
###### 代码共享:
使用父类引用来处理多个子类对象,可以将共享的代码抽象到父类中,避免了重复编写相似的代码,提高了代码的重用性。
#### 缺点:
###### 编译时类型检查不足:
在向下转型时,如果没有进行适当的类型检查,可能会导致编译时的错误或者运行时的异常。因此,必须小心地进行类型检查和转换,以避免潜在的错误。
###### 安全性问题:
类型转换可能会引入安全性问题。如果没有正确地进行类型检查,可能会在运行时出现 ClassCastException 异常,从而导致程序崩溃。
###### 可读性和维护性:
大量的类型转换可能会使代码更难以阅读和理解。特别是在复杂的继承关系中,类型转换可能会导致代码的复杂性,降低代码的可读性和可维护性。
###### 违背封装原则:
使用类型转换可能会违反封装原则,因为它允许在外部访问子类特有的方法和属性,从而可能破坏了封装的隔离性。
总的来说,子类和父类之间的类型转换在合适的情况下可以提高代码的灵活性和重用性,但也需要小心地进行类型检查,避免潜在的错误和安全性问题。最佳实践是使用类型转换时要充分理解其优缺点,并根据具体情况做出明智的决策。
#### 父类引用指向子类的对象
把子类转换为父类,(替代老子 )向上转型,会丢失子类自己原来的特有的方法
把父类转换为子类,(剥夺地位)向下转型,强制转换(丢失精度 ),才调用子类方法
**类似,子类转父类,会丢失方法,子类不能继承父类的私有方法
;
而父类转子类,(Person-->dog 高转低 向上强转 )只需要强制转换,还能使用子类的方法!多好**
方便方法的调用(转型),减少重复的代码,简洁
### 14
静态变量可以直接用类名访问,也称类变量
静态变量(或方法)对于类,所有对象(实例)共享
静态变量可以直接调用,但是非静态变量不可以直接调用
### 14 Static
### 作用:
#### 1. 静态变量(Static Variables):
静态变量是属于类而不是对象的变量。它在类的所有对象之间共享相同的值。在创建一个对象时,所有该类的实例都会共享同一个静态变量的值。静态变量通过使用 static 关键字来声明。
java
Copy code
class Counter {
static int count = 0; // 静态变量,所有 Counter 对象共享这个值
public Counter() {
count++; // 每次创建对象时,计数器增加
}
static int getCount() {
return count; // 静态方法可以访问静态变量
}
}
public class Main {
public static void main(String[] args) {
Counter c1 = new Counter();
Counter c2 = new Counter();
System.out.println("对象数量:" + Counter.getCount()); // 输出:对象数量:2
}
}
#### 2. 静态方法(Static Methods):
静态方法是属于类而不是对象的方法。它可以在不创建类的实例的情况下被调用。静态方法通过使用 static 关键字来声明。
java
Copy code
class MathUtil {
static int add(int a, int b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
int result = MathUtil.add(5, 3); // 调用静态方法
System.out.println("结果:" + result); // 输出:结果:8
}
}
#### 3. 静态代码块(Static Initialization Block):
静态代码块在类被加载时执行,通常用于进行类的初始化操作。它也使用 static 关键字来声明。
java
Copy code
class MyClass {
static int count;
static {
count = 10; // 静态代码块在类加载时执行
}
}
public class Main {
public static void main(String[] args) {
System.out.println("Count:" + MyClass.count); // 输出:Count:10
}
}
总的来说,static 关键字用于创建与类本身相关联的属性和方法,而不是与类的实例相关联。希望这些例子能帮助你理解 static 的概念。如果还有疑问,随时提问!
#### 代码块
```java
静态区代码加载类时一起被初始化,最早执行且只执行一次(第一次new)
public class Person{
{
System.out.println("匿名代码块");
}
static {
System.out.println("静态代码块");
}
public Person(){
System.out.println("构造方法");
}
public static void main(String[] args){
Person person = new Person();
System.out.println("=====================")
Person person2 = new Person();
System.out.println("=====================")
Person person3 = new Person();
}
}
//静态代码块
//匿名代码块
//构造方法
//======
//匿名代码块
//构造方法
```
#### Math->随机数:
###### //静态导入包
```java
import static java.lang.Math.random;
public class Application {
public static void main(String[] args) {
//第一种随机数,不用导包
System.out.println(Math.random());
//0.7562202902634543
//第二种随机数,静态导入包
System.out.println(random());
//0.5391606223844663
}
}
```
#### -不能重写的方法
1、static方法,属于类它不属于实例 2、final 常量 3、private 私有类不能重写
### 15 抽象类 子类强制重写抽象方法 老子省事 模板设计模式
创建一个人,必须要有五官、身高体重。但是长多帅、多高、多重,你可以自己决定。
接口可以多继承,抽象单继承

abstract修饰的类就是抽象类,修饰的方法就是抽象方法
抽象类中可以没有抽象方法,但有抽象方法的类一定要声明为抽象类
抽象类不能使用new来创建对象,它是用来让子类继承的
抽象方法只有方法的声明,没有实现,让其子类实现
子类继承抽象类,必须实现抽象类的所有方法, 否则该子类也要声明为抽象类
编译器给抽象类添加了一个无参构造方法。
### 16【接口】
#### 接口最能体现OOP的精髓,对 对象 的抽象
#### 抽象类是对事物属性的抽象,接口是对行为的抽象
public abstract class Person{
}
pubnlic class Students enxtends Person{
@Override
public void do Something(){
}
}
类里面有方法的实现,接口里面只有方法的定义。
因为它是抽象的(空方法模版),所以在类中实现(调用)接口的时候,必须要进行方法重写才能使用。
- 在Java编程语言中是一个抽象类型,是抽象对象的集合,对象通常以interface关键字来声明。
#### 普通类:只有具体实现 属性+方法
##### 抽象类:具体实现和规范(抽象方法)共存 模版设计
##### 接口:只有规范,无法自己实现 约束规范
##### 约束和实现分离->面向接口编程
接口就是规范,定义一组规则,**它的本质是契约**,制定好之后大家都要遵守。
OO的精髓,是对对象的抽象,最能体现这一点的就是接口。为什么我们讨论设计 模式都只针对具备了抽象
能力的语言(比如c++、java、c#等),就是因为设计模式所研究的,实际上就是如何合理的去抽象。
#### 接口的特性
接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字
接口中的方法都是公有的。
实现
#### 1 接口的声明
```java
[可见度] interface 接口名称 [extends 其他的接口名] {
// 声明变量
// 抽象方法
}
```
```java
/**
*用户接口,需要实现类
*锻炼抽象的思维
*/
public interface UserService{
//定义的属性默认是静态常量:public static final
int age = 10;
//定义的方法默认是公共抽象:public abstract 因此可以省略 不写
public abstract void add(String str);
void delete(String str);
void update(String str);
void query(String str);
}
public interface TimeService{
void timer();
}
```
#### 2 接口的实现
```java
/*
抽象类用继承:extends
接口用实现:implements
类可以实现接口,需要实现所有方法!
利用接口实现伪多继承~
*/
public class UserServiceImplement implements UserService,TimeService{
@Override
public void add(String str){
}
@Override
public void delete(String str){
}
@Override
public void update(String str){
}
@Override
public void query(String str){
}
@Override
public void timer(){
}
}
```
类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常
#### 在实现接口的时候,也要注意一些规则:
#### Mac快捷键是command+回车
###### 1. 一个类只能继承一个类,但是能实现多个接口
###### 2. 一个接口能继承另一个接口,这和类之间的继承比较相似
###### 继承
###### 3. 接口的继承使用extends关键字,子接口继承父类接口的方法
```java
//文件名:Sports.java
public interface Sports{
public void setHomeTeam(String name);
public void setVisitingTeam(String name);
}
//文件名:Football.java
public interface Foorball extends Sports{
public void homeTeamScored(int points);
public void visitingTeamScored(int points)
public void endOfQuarter(int quarter);
}
//文件名:Hockey.java
public interface Hockey extends Sports{
public void homeGoalScored();
public void visitingGoalScored();
public void endOfPeriod(int period);
public void overtimePeriod(int ot);
}
```
#### 多继承
###### 类不允许多继承
###### 接口允许多继承
接口与类相似,一个接口可以有多个方法
#### 接口与类的区别
接口不能被实例化
接口没有构造方法
接口中所有的方法必须是抽象方法
接口不能包含成员变量,除了static和final变量
接口不是被类继承,而是被类实现
接口支持多继承(实现类(implements) 可以实现多个接口)
实现类必须要重写接口中的方法
JDK8之后的新特性,支持在接口中实现具体方法,但需要default修饰。default修饰方法只能在接口中使用。
### 17 内部类
内部类:在一个类的内部再定义一个类
class A{
class B{
}
}
A是B的外部类,B是A的内部类。
#### 1 成员内部类
###### 定义成员内部类
```java
public class Outer{
private int id = 10;
public void out(){
System.out.println("外部类的方法");
}
//成员内部类
public class Inner{//若内部类加上static 静态 则getOuterId()方法失效。因为 静态
public void inner(){
System.out.println("内部类的方法");
}
//可以直接使用外部类的属性/方法
public void getOuterId(){
System.out.println("内部类调用外部类属性和方法");
//创建成员内部类之前肯定要创建外部类对象
//即使id不是静态变量,out不是静态方法,但创建外部类对象时已经存在。
System.out.pirntln(id);
out();
}
}
}
```
#### 实现内部类
```java
import com.oop.demo10.Outer;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();//通过这个外部类来实例化内部类
Outer.Inner inner = outer .new Inner();
inner.getID();
```
#### 匿名内部类
public class Application{
public static void main(String[] args){
//匿名内部类在多线程中使用,到时候再深究
Thread thread = new Thread(new Runnable(){
@Override
public void run(){
System.out.println("匿名内部类实现线程的逻辑操作");
}
});
//开启操作
thread.start();
}
}
# 06 异常
### 1 Error 和 Exception
异常
#### 1.什么是异常
实际工作中,遇到的情况不可能是非常完美的。比如:你写的某个模块,用户输入不一定符合你的要求、你的程序要打开某个文件,这个文件可能不存在或者文件格式不对,你要读取数据库的数据,数据可能是空的等。我们的程序再跑着,内存或硬盘可能满了。等等。
软件程序在运行过程中,非常可能遇到刚刚提到的这些异常问题,我们叫异常,英文是:Exception,意思是例外。这些,例外情况,或者叫异常,怎么让我们写的程序做出合理的处理。而不至于程序崩溃。
异常指程序运行中出现的不期而至的各种状况如:文件找不到、网络连接失败、非法参数等。异常发生在程序运行期间它影响了正常的程序执行流程。
要理解Java异常处理是如何工作的,需要掌握以下三种类型的异常:
#### 2 三种类型的异常
###### 检查性异常:
最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
###### 运行时异常:
运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
###### 错误ERROR:
错误不是异常,而是脱离程序员控制的冋题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
#### 3.异常体系结构

Java把异常当作对象来处理,并定义一个基类 java. lang.Throwable作为所有异常的超类。
在 Java API中已经定义了许多异常类,这些异常类分为两大类,错误Error和异常 Exception。
在这里插入图片描述
#### Error
Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写者所执行的操作无关。
Java虚拟机运行错误( Virtual Machine Error),当JVM不再有继续执行操作所需的内存资源时,将出现 OutofMemory Error。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
还有发生在虛拟机试图执行应用时,如类定义错误( NoClass Deffound error)、链接错误( Linkage Error)。这些错误是不可查的,因为它们在应用程序的控制和处理能力之外,而且绝大多数是程序运行时不允许出现的状况。
#### Exception
##### 运行时异常(还有非运行异常 检查异常)
在 Exception分支中有一个重要的子类 Runtime Exception(运行时异常)
ArraylndexOutOfBoundsException(数组下标越界)
NullPointerException(空指针异常)
ArithmeticException(算术异常)
Missing Resource Exception(丢失资源)
ClassNotFound Exception(找不到类)等异常,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。
这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生;
#### Error和 Exception的区别:
###### Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虛拟机(JVM)一般会选择终止线程;
###### Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常。
### 2 Java异常处理机制与处理异常
### 抛出异常
### 捕获异常
异常处理五个关键字:
try、catch、 finally、throw、throws
```java
public static void main(String[] args) {
int a=1;
int b=0;
try{
System.out.println(a/b);
}catch (Error e){
System.out.println("Error");
}catch(Exception e){
System.out.println("Exception");
}catch (Throwable t){
System.out.println("Throwable");
}finally {
System.out.println("finally");
}
}
public void a(){b();}
public void b(){a();}
```
```java
int a = 1;
int b = 0;
try{
// try 监控区域
if(b == 0)
{
// 主动抛出异常,一般在方法上使用
throw new ArithmeticException();
}
System.out.println(a/b);
}catch (ArithmeticException e){
// catch 捕获异常
System.out.println("程序出现异常,变量b不能为0");
}catch (Throwable t){
// catch 可以有多个
t.printstackTrace(); // 打印错误的栈信息
System.out.println("从小到大捕获异常");
}finally {
// 处理善后工作
System.out.println("finally"); // 可以不要,多用于IO、资源的关闭。
}
// 假设在这个方法中,处理不了这个异常,在方法上抛出异常。
public void test(int a,int b) throws ArithmeticException{
if(b == 0)
{
throw new ArithmeticException();
}
}
```
#### throws和throw的区别
是不管程序有没有异常,只要执行到throw语句就一定会抛一个异常
快捷键:mac command+option+T
### 3.自定义异常
使用Java内置的异常类可以描述在编程时岀现的大部分异常情况。除此之外,用户还可以自定义异常。用户自定义异常类,只需继承 Exception类即可。
在程序中使用自定义异常类,大体可分为以下几个步骤:
创建自定义异常类。
在方法中通过 throw关键字抛出异常对象。
如果在当前抛出异常的方法中处理异常,可以使用try- catch语句捕获并处理;否则在方法的声明处通过 throws关键字指明要抛岀给方法调用者的异常,继续进行下一步操作。
在出现异常方法的调用者中捕获并处理异常。
在这里插入图片描述
5.总结
处理运行时异常时,采用逻辑去合理规避同时辅助 try-catch ;
处理在多重 catch块后面,可以加一个 catch( Exception)来处理可能会被遗漏的异常;
对于不确定的代码,也可以加上try- catch,处理潜在的异常;
尽量去处理异常,切忌只是简单地调用 printStackTrace0去打印输出;
具体如何处理异常,要根据不同的业务需求和异常类型去决定;
尽量添加 finally!语句块去释放占用的资源。
-=========================
Java把溢出当做对象来处理,并定义了一个基类Java.lang.Throwable作为所有异常的超类。
Java语言定义了许多异常类在Java.lang标准包中,主要分为Error和Exception两大类。
img
五个关键字try、catch、finally、throw、throws
使用try和catch关键字可以捕获异常。try/catch代码块放在异常可能发生的地方。
try/catch代码块中的代码称为保护代码。
finally区可以不要,在IO流,资源关闭时使用。
捕获多个溢出:从小到大!
IDEA快捷键:选中健康区域代码-->Ctrl + Alt + T
抛出异常
throws是用来声明一个方法可能抛出的所有异常信息,throws是将异常声明但是不处理,而是将异常往上传,谁调用我就交给谁处理。而throw则是指抛出的一个具体的异常类型
throws是用在方法名尾部,可以声明抛出多个溢出,多个溢出之间用逗号隔开。
import java.io.*;
public class className{
public void withdraw(double amount) throws RemoteException,InsufficientFundsException{
//Method implementation
}
//Remainder of class definition
}
throw是用在方法体内,主动抛出异常
public class ThrowTest{
public static void main(String[] args){
int a = 1;
int b = 0;
try{
System.out.println(divide(a,b));
}catch (Exception e){
System.out.println("分母不能为0");
//e.printStackTrace();
}
}
public static double divide(int a,int b){
if(b == 0){
//主动抛出异常
throw new ArithmeticException();
}
return 1.0*a/b;
}
}
自定义异常
在这里插入图片描述
//自定义的异常类
public class MyException extends Exception{
private int detail;
public Myexception(int a){
this.detail = a;
}
//异常的处理信息
//tostring
@Override
public String toString(){
return "Myexception{" + "detail=" + detail + "}";
}
}
public class Appcication{
//可能存在异常方法
static void test(int a) throws MyException{
System.out.println("传递的参数为:" + a);
if(a>10){
throw new MyException(a);//抛出
}
System.out.println("ok");
}
}
public static void main(String[] args){
try{
test(11);
}catch (MyException e){
System.out.println("MyException=>" + e);
}
}
#### 总结
处理运行是异常时,采用逻辑去合理规避,同时辅助try-catch处理
在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
对于不确定的代码,也可以加上try-catch,处理潜在的异常
尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出
具体如何处理异常,要根据不同的业务需求和异常类型去决定
尽量添加finally语句块去释放占用的资源。