Java编程基础(第二阶段)
Day-09 面向对象(高级)
- 类变量和类方法
- 理解main方法语法(static)
- 代码块
- 单例设计模式
- final关键字
- 抽象类
- 接口
- 内部类
0039 类变量和类方法
类变量
-
类变量,也叫静态变量。用
static
修饰 -
特点,会被该类的所有对象实例共享
//定义一个变量 count ,是一个类变量(静态变量) static 静态 //该变量最大的特点就是会被Child 类的所有的对象实例共享 public static int count = 0;
-
这个count是放在
堆
里面的 -
在类加载的时候就生成,静态域中。保存在class实例的最后
-
-
什么是类变量
- 类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时取到的都是相同的值;同样任何一个该类的对象去修改它时,修改的也是同一个变量。这个从前面的图也可看出来。
-
如何定义类变量
访问修饰符 static 数据类型 变量名;//[推荐] static 访问修饰符 数据类型 变量名;
-
如何访问类变量VisitStatic.java
-
类名.类变量名; //或者: 对象名.类变量名;//【静态变量的访问修饰符的访问权限和范围和普通属性是样的。】
-
推荐使用:
类名.类变量名
-
-
类变量与实例变量(普通属性)区别
- 类变量必须通过static修饰。
- 类变量是该类的所有对象共享的,而实例变量是实例的单个对象独享的。
- 实例变量不能通过类名.类变量名方式访问。
- 类变量是在类加载时就初始化了,也就是说,即使你没有创建对象,只要类加载了,就可以使用类变量了。
- 类变量的生命周期是随类的加载开始,随着类消亡而销毁。[Monster.name]
类方法
-
类方法,也叫静态方法
-
定义方式
访问修饰符 static 数据类型 方法名(){};//[推荐] static 访问修饰符 数据类型 方法名(){};
-
类方法的调用
- 和类变量一样,通过类名来调用
-
类方法经典的使用场景
- 当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法提高开发效率
- 该类方法拿来做工具类中的方法最合适。不用创建对象就可以调用该方法
- 比如:工具类中的方法util
- Math类、 Arrays类、 Colllections集合类看下源码
- 其中:Array.sort();Math.sqrt();
- 小结
- 在程序员实际开发,往往会将一些通用的方法,设计成静态方法,这样我们不需要创建对象就可以使用了,比如打印一维数组,冒泡排序,完成某个计算任务等.[举例说明…
-
类方法使用细节
- 类方法中不存在this;普通方法中隐藏着this的参数;
- 类方法可以直接通过类名调用,也可以通过对象调用;
- 类方法中不允许使用和对象有关的关鍵字,比如this和 super。普通方法(成员方法)可以。
- 类方法(静态方法)中只能访问静态变量或静态方法。【如何理解】,普通成员方法,既可以访问普通变量(方法),也可以访问静态变量(方法)。
- 小结:静态方法,只能访问静态的成员,非静态的方法,可以访问静态成炅和非静态成员(必须遵守访问权限)
main方法
-
深入理解main方法
- 解释main方法的形式: public static void main( String[]args){}
-
main方法时虚拟机调用
-
java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是 public
-
java虚拟机在执行main()方法时不必创建对象,所以该方法必须是 static
-
该方法接收 String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数案例演示,接收参数
-
javac Hello
-
java Hello “tom” “jack”.这里的tom、jack就是传给args数组的元素,在运行的时候,通过dos命令行传进去.
public static void main(String[] args) { for (int i = 0; i < args.length; i++) { System.out.println(args[i]); }
-
-
java 执行的程序 参数1 参数2 参数3.
-
在idea中传参要在这个位置
- 运行结果
- 运行结果
-
main方法是一个静态方法,他的使用遵循类方法的规则,即只能调用静态成员。
private static int n=1999; int s = 900; public static void main(String[] args) { System.out.println(Main_.n); // System.out.println(Main_.s);//不能访问非静态成员 //通过创建对象访问 Main_ main_ = new Main_(); System.out.println(main_.s); for (int i = 0; i < args.length; i++) { System.out.println(args[i]); } }
0040 代码块
-
基本介绍
-
代码化块又称为初始化块,属于类中的成员[即是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过包围起来。
-
但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或刨建对象时隐式调用。
-
基本语法
[修饰符]{ 代码 }
-
注意
- 修饰符可选,要写的话,也只能写 static
- 代码块分为两类,使用 static修饰的叫静态代码块,没有 static修饰的,叫普通代码块
- 逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)
;
号可以写上,也可以省略。
-
-
代码块的好处
- (普通)代码块是对构造器的补充机制
- 假如类中有多个构造器,我们无论调用哪一个构造器,都会优先执行代码块中的内容,然后在执行构造器初始化中的内容。
-
细节和注意事项
-
static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。
- 无论创建多少个对象,类只会被加载一次!!!!
- 如果是普通代码块,每刨建一个对象,就执行一次。和类是否加载没有直接关系
-
类什么时候被加载✨
①创建对象实例时(new…,)
②创建子类对象实例时,父类也会被加载【父类先,子类后】
③使用类的静态成员时,
-
普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就会调用一次。
- 如果只是使用类的静态成员时,普通代码块并不会执行
- 小结:1. static代码块是类加载时,执行,只会执行一次。普通代码块是在创建对象时调用的,创建一次,调用一次类加载的3种情况,需要记住
-
创建一个对象时,在一个类调用顺序是:(重点,难点)🎈
①调用静态代码块和静态属性初始化(注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的顺序调用)
②调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义顺序调用)
③调用构造方法
-
构造器的最前面其实隐含了 super()和调用普通代码块,静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器执行的。
-
我们看一下刨建一个子类时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下
①父类的静态代码块和静态属性(优先级一样,按定乂顺序执行)
②子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
③父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
④父类的构造方法
⑤子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
⑥子类的构造方法∥/面试题
A,B,C类演示[10Min]55 CodeblockDetail04java
测试代码 -
静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。
-
0041 单例设计模式
-
什么是单例设计模式
- 所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法;
- 单例模式有两种方式:1)饿汉式2)懒汉式。
-
饿汉式
-
构造器私有化:防止直接new
-
类的内部创建对象:
-
向外暴露一个静态的公共方法:getInstance()
-
代码实现
注意:在类里面创建的private对象在类加载的时候就创建了,你不能new一个。
class GirlFriend{ private String name; //2.在类的内部创建一个对象,单例 private static GirlFriend g1 = new GirlFriend("jack"); //1.将构造器私有化,类的外部不能在new一个对象 private GirlFriend(String name){ this.name = name; } //3.向外暴露一个静态的公共方法:getinstance public static GirlFriend getInstance(){ return g1; } public void say(){ System.out.println("jack是我唯一的女朋友"); } }
🎈缺点:对象是重量级的,饿汉式可能创建了对象,但是不会使用,造成了资源的浪费。
-
-
懒汉式
-
将构造器私有化
-
定义一个static静态对象
-
定义一个public的static方法,可以返回一个Cat对象
//一个人只能养一只猫,即只能创建一个Cat对象 class Cat{ private String name; public static int n1 = 999; //2.定义一个static静态对象 private static Cat cat;//相对于饿汉式,此处没有new //1.将构造器私有化 private Cat(String name) { this.name = name; } //3.定义一个public的static方法,可以返回一个Cat对象 public static Cat getInstance(){ //如果没有cat对象,就创建一个,如果已经有了一个cat对象 //,就不会再创建,用于只有一个 if(cat==null) { cat = new Cat("小猫咪"); } return cat; } }
-
注意:懒汉式,只有当用户调用getInstance()时,才会创建,保证了资源的合理化
- 懒汉式存在线程安全问题
-
0042 final关键字
-
基本介绍
Finalo1.java- final:最后的最终的
- final可以修饰类、属性、方法和局部变量。
- 在某些情况下程序员可能有以下需求,就会使用到final
- 当不希望类被继承时可以用 final修饰.【案例演示】
- 当不希望父类的某个方法被子类覆盖/重写( override)时,可以用final关键字修饰。【案例演示访问修饰符fna返回类型方法名】
- 当不希类的的某个属性的值被修改可以用final修饰
- 【案例演示 public final double TAX_RATE=0.08】
- 当不希望某个局部变量被修改,可以使用final修饰
- 【案例演示 final double TAX_RATE=008】
-
final使用细节
- final修饰的属性又叫常量,一般用XX_XX_XX来命名。
- final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以再如下位置之一:
- 定义时:
public final double TAX_RATE=0.08;
- 在构造器中
- 在代码块中
- 定义时:
- 如果final修饰的属性是静态的,则初始化的位置只能是:
- 定义时
- 在静态代码块中
- 不能在构造器中赋值【没有静态构造器】
- 注意:静态不能和对象有关联✨,因为静态的东西是在类加载的时候就执行。
- final类不能继承,但是可以实例化对象
- 如果类不是final类,但是有final方法,则该方法虽然不能重写,但可以被继承。
- 如果一个类已经是final类,没有必要再对里面的方法final。
- final不能修饰构造器
- final往往与static搭配起来使用,往往效率更高,不会导致类加载
- 包装类( Integer, Double, float, Boolean等都是final) String也是 final类。
0043 抽象类abstract
-
当父类的某些方法,需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类。【父类方法的不确定性】
abstract class Animal{ private String name; public Animal(String name) { this.name = name; } //这里的eat方法其实没有什么意义- // --父类方法不确定性的问题 //将该方法设计为抽象方法abstract //抽象方法就是没有实现的方法,即没有方法体 //当一个类中存在抽象方法是=时,需要将该类声明为抽象类 // public void eat(){ // System.out.println("这是一个动物,但是不知道吃什么?"); // } public abstract void eat(); }
-
基本介绍
- 用 abstract关键字来修饰一个类时这个类就叫抽象类
- 访问修饰符 abstract类名{
- 用 abstract关键字来修饰一个方法时这个方法就是抽象方法
- 访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
- 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类。
- 抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多
- 用 abstract关键字来修饰一个类时这个类就叫抽象类
-
抽象类的细节
- 抽象类不能被实例化
- 抽象类不一定包含抽象方法
- 含有抽象方法的类,一定要被abstract修饰
- abstract只能修饰类和方法,不能修饰属性或者构造器。
- 抽象类可以有任意成员【抽象类本质还是类】,比如:非抽象方法、构造器、静态属性等等。
- 抽象方法不能有主体,即不能实现如图所示
- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。[举例A类B类C类]
- 抽象方法不能用
private\final\static
三个关键字修饰。因为这些关键字都是和重写相违背的。
- 抽象类不能被实例化
-
抽象类最佳实践–模板设计模式
-
需求
- 有多个类,完成不同的任务job
- 要求能够得到各自完成任务的时间
- 请编程实现 TestTemplate.java
-
感情的自然流露
- 先用最容易想到的方法
- 分析问题,提出使用模板设计模式
-
0044 接口 interface
- 抽象类的"进化体", 接口内方法,默认有abstract, 不用写。这样理解
- 抽象类只能单继承,接口可以有很多个实现
基本介绍
-
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来。
-
语法:
interface 接口名{ 属性; 方法; }
-
类实现接口的语法:implements
class 类名 implements{ 自己属性; 自己方法; 必须实现接口的所有抽象方法; }
-
小结
- 在Jdk7.0前接口里的所有方法都没有方法体。(即都是抽象方法)
- Jdk8.0后接口可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现。
-
在接口中,抽象方法可以省略abstract关键字
-
要在接口内实现具体的方法,要在最前面加default关键字。
public interface UsbInterface { public void start();//抽象方法 public void end();//抽象方法 default public void say(){ System.out.println("szy.....say"); } //静态方法 public static void ok(){ System.out.println("szy.....ok") } }
使用细节和注意事项
-
接口不能被实例化
-
接口中所有的方法是public 方法。接口中抽象方法,可以不用abstract修饰。(抽象方法没有方法体)
-
一个普通的类实现接口,就必须将该接口的所有的抽象方法实现(重写)
- Alt /:快捷键,方法重写
-
抽象类实现接口,可以不用实现接口的方法(可以理解:接口计算一种特殊的抽象类)
-
一个类同时可以实现多个接口
class Cat implements Ia,Ib...
-
接口中的属性只能是fnal的,而且是 public static final修饰符。
-
比如
int a=1;
实际上是public static final int a=1;
(必须初始化),在实际开发过程中那些关键字不用写,隐藏有。 -
接口中属性的访问形式:
接口名.属性名;
-
-
一个接口不能继承其它的类, 但是可以继承多个别的接口(接口和接口的关系也是继承)
interface A extends B,C{}
-
接口的修饰符只能是 public和 默认,这点和类的修饰符是一样的。
实现接口vs继承类
- 小结:
- 单继承,多实现
- 当子类继承了父类,就自动的拥有父类的功能
- 如果子类需要扩展功能,可以通过实现接口的方式扩展
- 可以理解:实现接口是对java单继承机制的一种补充
- 接口和继承解决的问题不同
- 继承的价值主要在于:解决代码的复用性和可维护性
- 接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法
- 接口比继承更加灵活
- 接口比继承更加灵活,继承是满足is-a的关系,而接口只需满足like-a的关系。
- 接口在一定程度上实现代码解耦【接口规范性+动态绑定机制】
接口多态特性
-
接口类型可以指向实现了该接口的对象实例
-
类定义的进一步完善
0045 内部类【4种】✨🎈
-
基本介绍
- 一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类( inner class),嵌套其他类的类称为外部类 (outer class)。
- 是我们类的第五大成员【思考:类的五大成员是哪些?】内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。
- 类的五大成员
- 属性、方法、构造器、代码块、内部类。
-
基本语法
class Outer{ /外部类 class Inner{ /内部类 } } class Other{ /外部其他类 }
-
内部类的分类
- 🎈定义在外部类局部位置上(比如方法內)
- 局部內部类(有类名)
- 匿名内部类(没有类名—重点)
- 🎈定义在外部类的成员位置上
- 成员内部类(没用 static修饰)
- 静态内部类(使用 static修饰)
- 🎈定义在外部类局部位置上(比如方法內)
1. 局部内部类
-
局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。LocalInnerClass.java
-
可以直接访问外部类的所有成员,包括私有的。
-
不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用访问修饰符的。但是可以用final修饰,因为局部变量也可以使用final.
-
作用域:仅仅在定义它的方法或代码块中
-
外部类在方法中,可以实例化内部类对象,然后调用方法。
-
外部其他类不能访问该类的内部类【因为内部类地位是一个局部变量】
-
如果外部类和内部类的成员重名时,默认遵循就近原则,
如果想访问外部类的成员,则可以使用
外部类名.this.成员
去访问。
-
2. 匿名内部类🎈
-
解读:AnonymousInnerClass.java
- 本质是类
- 内部类
- 该类没有名字
- 匿名内部类还是一个对象
-
说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
-
基本语法
new 类或者接口(参数列表){ 类体 };
-
基于接口的匿名内部类
class Outer04{ private int n1=10; public void method(){ //基于接口的匿名内部类 //tiger的编译类型:IA接口 //tiger的运行类型:这个匿名内部类Outer04$1 /* 底层 class XX implements IA{ //XX:Outer04$1,也就是匿名内部类真正的名字,系统分配的,用完一次就没有了 @Override public void cry() { System.out.println("老虎机…………"); } } */ //创建匿名内部类之后,jdk马上又创建了一个对象实例tiger IA tiger = new IA() { @Override public void cry() { System.out.println("老虎机…………"); } }; System.out.println("tiger的运行类型:"+tiger.getClass()); tiger.cry(); } } interface IA { public void cry(); }
-
基于类的匿名内部类
class Outer04{ private int n1=10; public void method(){ //基于类的匿名内部类 //father编译类型:Father //father运行类型:这个匿名内部类Outer04$2 //也直接返回了这个匿名内部类的对象father Father father = new Father("jack"){ //匿名内部类没有构造器 @Override public void test() { System.out.println("匿名内部类重写了Father的test方法"); } }; father.test(); System.out.println("father的运行类型:"+father.getClass()); } } class Father { public Father(String name){} public void test(){} }
-
匿名内部类的使用细节
-
匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义
-
同时它本身也是一个对象,因此从语法上看,它既有定类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法。
-
两种方式调用方法
-
如果外部类和内部类的成员重名时,默认遵循就近原则,
如果想访问外部类的成员,则可以使用
外部类名.this.成员
去访问。
-
-
匿名内部类实践
- 把匿名内部类当作实参传递,简洁高效。
InnerClassExercise01.java
- InnerClassExercise02.java
- 把匿名内部类当作实参传递,简洁高效。
3. 成员内部类
- 说明:成员内部类是定义在外部类的成员位置,并且没有
static
修饰
-
可以直接访问外部类的所有成员,包括私有的
-
可以添加任意的访问修饰符【把它当初跟那个一个属性或者成员】
-
和外部类的其他成员一样,为整个类体,比如前面案例,在外部类的成员方法中创建成员内部类对象,再调用方法。
-
成员内部类-访问–>外部类(比如:属性)[访问方式:直接访向]〔说明
-
外部类–访问—>内部类(说明)访问方式:创建对象,再访问
-
外部其他类-访问->成员内部类
MemberInnerClass01.java
Outer08 outer08 = new Outer08(); //外部其他类,使用成员内部类的三种方式 //老韩解读 // 第一种方式 // outer08.new Inner08(); 相当于把 new Inner08()当做是outer08成员 // 这就是一个语法,不要特别的纠结. Outer08.Inner08 inner08 = outer08.new Inner08(); inner08.say(); // 第二方式 在外部类中,编写一个方法,可以返回 Inner08对象 Outer08.Inner08 inner08Instance = outer08.getInner08Instance(); inner08Instance.say();
-
如果外部类和内部类的成员重名时,内部类访问的话,默认遵循就近原则,如果想访问外部类的成员,则可以使用(
外部类名.this.成员
)去访问。
4. 静态内部类
-
必须用static修饰。StaticInnerClass.java
-
放在外部类的成员位置,用static修饰
-
可以直接访问外部类的所有静态成员,包括私有的,但是不能访问非静态成员。
-
可以添加任意的访问修饰符【四种】,因为它本身是一个成员
-
作用域:整个类体
//外部其他类 使用静态内部类 //方式1 //因为静态内部类,是可以通过类名直接访问(前提是满足访问权限) Outer10.Inner10 inner10 = new Outer10.Inner10(); inner10.say(); //方式2 //编写一个方法,可以返回静态内部类的对象实例. Outer10.Inner10 inner101 = outer10.getInner10(); System.out.println("============"); inner101.say(); //返回方法是静态时 Outer10.Inner10 inner10_ = Outer10.getInner10_(); System.out.println("************"); inner10_.say();
-
如果外部类和静态内部类的成员重名时,静态内部类访问的时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.成员)去访问
Day-10 枚举和注解
0046 枚举
-
基本介绍
- 枚举对应英文( enumeration,简写enum)
- 枚举是一组常量的集合。
- 可以这里理解:枚举属于一种特殊的类,里面只包含一组有限的特定的对象。
-
两种方式
- 自定义类实现枚举
- enum关键字实现枚举
-
增强for循环
1. 自定义类实现枚举
-
可以提供getXXX方法,不需要提供 setXXX方法,因为枚举对象值通常为只读
-
对枚举对象/属性使用fina+ static共同修饰,实现底层优化
-
枚举对象名通常使用全部大写,常量的命名规范。
-
枚举对象根据需要,也可以有多个属性// Enumeration02.java
public static final Season SPRING = new Season("春天", "温暖"); public static final Season SUMMER = new Season("夏天", "炎热"); public static final Season AUTUMN = new Season("秋天", "凉爽"); public static final Season WINTER = new Season("冬天", "寒冷");
2. enum关键字实现枚举
-
当我们使用enum关键字开发一个枚举类时,默认会继承Enum类,而且是一个final类。[如何证明]。
javap
: 反编译指令
-
传统的
public static final Season SPRING= new Season("春天","温暖")
简化成SPRING("春天","温暧")
,这里必须知道,它调用的是哪个构造器。 -
如果使用无参构造器创建枚举对象,则实参列表和小括号都可以省略。
-
当有多个枚举对象时,使用
逗号
间隔,最后有一个分号结尾。 -
枚举对象必须放在枚举类的行首。Enumeration03.java
//使用enum关键字实现枚举类
//将常量(对象放在最前面)
//如果有多个常量,使用逗号间隔
SPRING("春天", "温暖"),SUMMER("夏天", "炎热"),
AUTUMN("秋天","凉爽"),WINTER("冬天","寒冷");
private String name;
private String description;//描述
- 说明:使用关键字enum时,会隐式继承Eum类,这样我们就可以使用Enum类相关的方法。看下源码定义
Modifier and Type | Method and Description |
---|---|
protected Object | clone() 抛出CloneNotSupportedException。 |
int | compareTo(E o) 将此枚举与指定的对象进行比较以进行订购[比较的是编号,类似于数组下标],返回的是两个下标相减的值。 |
boolean | equals(Object other) 如果指定的对象等于此枚举常量,则返回true。 |
protected void | finalize() 枚举类不能有finalize方法。 |
类<E> | getDeclaringClass() 返回与此枚举常量的枚举类型相对应的Class对象。 |
int | hashCode() 返回此枚举常量的哈希码。 |
String | name() 返回此枚举常量的名称,与其枚举声明中声明的完全相同。 |
int | ordinal() 返回此枚举常数的序数(其枚举声明中的位置,其中初始常数的序数为零)。 |
String | toString() 返回声明中包含的此枚举常量的名称。 |
static <T extends Enum<T>>T | valueOf(类<T> enumType, String name) 返回具有指定名称的指定枚举类型的枚举常量。 |
类[] | values() 返回当前枚举类中的所有常量 |
- 使用enum关键字后,就不能再继承其它类了,因为enum会隐式继承Enum,而Java是单继承机制。
- 枚举类和普通类一样,可以实现接口,如下形式。
enum 类名 implements接口1,接口2{}
0047 注解
-
注解( Annotation)也被称为元数据( Metadata),用于修饰解释包、类、方法、属性、构造器、局部变量等数据信息。
-
和注释一样,注解不影响程序逻辑,但注解可以被编译或运行,相当于嵌入在代码中的补充信息。
-
在 JavaSE中,注解的使用目的比较简单,例如标记过时的功能,忽略警告等。在 JavaEE中,注解占据了更重要的角色,例如:用来配置应用程序的任何切面,代替 java EE旧版中所遗留的繁冗代码和XML配置等。
基本介绍
-
使用 Annotation时要在其前面增加@符号并把该 Annotation当成一个修饰符使用。用于修饰它支持的程序元素。
-
三个基本的 Annotation:
-
@Override
:限定某个方法,是重写父类方法,该注解只能用于方法- @interface不是interface,而表示注解类
- @Target是修饰注解的注解,叫做元注解
- @interface不是interface,而表示注解类
-
@Deprecated
:用于表示某个程序元素(类,方法等)已过时。- 作用:新旧版本之间的过渡
-
@SuppressWarnings
:抑制编译器警告-
当我们不希望看到那些警告时,通过这个注解就可以让其消失
-
也是有作用域的
-
@SuppressWarnings({"all"})//抑制所有的警告
-
{" "}:里面还有很多类型
-
-
-
四种元注解
@Retention
//指定注解的作用范围,三种 SOURCE CLASS, RUNTIME@Target
//指定注解可以在哪些地方使用@Documented
/指定该注解是否会在 avadoc体现@merited
//子类会继承父类注解
Day-11 异常Exception
-
基本概念
- Java语言中,将程序执行中发生的不正常情况称为“异常”。併开发过程中的语法错误和逻辑错误不是异常)
- 执行过程中所发生的异常事件可分为两类
- Error(错误):Java虚拟机无法解决的严重问题。
- 如:JVM系统内部错误、资源耗尽等严重情况。
- 比如: StackOverflow Error栈溢出和OOM( out of memory),Error是严重错误,程序会崩溃。
- Exception:其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。
- 例如空指针访问,试图读取不存在的文件,网络连接中断等等,
- Exception分为两大类:运行时异常[]和编译时异常[]。
0048 异常体系图✨🎈
-
异常体系图
-
异常分为两大类,运行时异常和编译时异常
-
运行时异常,编译器检查不出来。一般是指编程时的逻辑错误,是程序员应该避免其出现的异常。
java.lang.RuntimeException
类及它的子类都是运行时异常。 -
对于运行时异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
-
编译时异常,是编译器要求必须处置的异常。
-
0049五大运行时异常
NullPointerException
空指针异常- 当应用程序试图在需要对象的地方使用null时,抛岀该异常,看案例演示NullPointerException01.java
ArithmeticException
数学运算异常- 当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。案例演示
ArrayIndexOutOfBoundsException
数组下标越界异常- 用非法索引访问数组时抛出的异常。如果索引为负或大于等于数组大小,则该索引为非法索引。ArrayIndexOutOfBoundsException03.java
ClassCastException
类型转换异常- 当试图将对象强制转换为不是实例的子类时,抛出该异常例如,以下代码将生成一个 ClassCastException。案例演示ClassCastException04.java
NumberFormatException
数字格式不正确异常- 当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常=>使用异常我们可以确保输入是满足条件数字。NumberFormatException05.java
0050 编译异常
- 常见的编译异常
- SQLException//操作数据库时,查询表可能发生异常
- IOEException/操作文件时,发生的异常
- FileNotFoundException//当操作一个不存在的文件时,发生异常
- ClassNotFoundException//加载类,而该类不存在时,异常
- OFException//操作文件,到文件未尾,发生异常
- IllegalArguementException//參数异常
0051 异常处理
-
基本介绍
- 异常处理就是当异常发生时,对异常处理的方式。
-
异常处理的方式
-
try-catch-finally
-
程序员在代码中捕获发生的异常,自行处理
-
处理机制图
-
-
throws
-
将发生的异常抛出,交给调用者(方法)来处理,最顶级的处理者就是JVM
-
处理机制图
-
-
try-catch
-
try- catch方式处理异常注意事项 TryCatchDetail,java
-
如果异常发生了,则异常发生后面的代码不会执行,直接进入到 catch块
-
如果异常没有发生,则顺序执行try的代码块,不会进入到 catch
-
如果希望不管是否发生异常,都执行某段代码(比如关闭连接、释放资源等)则使用如下代码- finally{}
try { int res = num1/num2; } catch (Exception e) { //e.printStackTrace(); System.out.println(e.getMessage());//输出异常信息 }finally { System.out.println("不管是否发生异常,始终执行的代码"); }
-
可以有多个 catch语句,捕获不同的异常(进行不同的业务处理),要求父类异常在后,子类异常在前,比如( Exception在后, NullPointerException在前),如果发生异常,只会匹配一个 catch,案例演示
//1.如果try代码块有可能有多个异常 //2.可以使用多个catch 分别捕获不同的异常,相应处理 //3.要求子类异常写在前面,父类异常写在后面 try { Person person = new Person(); //person = null; System.out.println(person.getName());//NullPointerException int n1 = 10; int n2 = 0; int res = n1 / n2;//ArithmeticException } catch (NullPointerException e) { System.out.println("空指针异常=" + e.getMessage()); } catch (ArithmeticException e) { System.out.println("算术异常=" + e.getMessage()); } catch (Exception e) { System.out.println(e.getMessage()); } finally { }
-
可以进行try- finally合使用,这种用法相当于没有捕获异常,因此程序会直接崩掉。
- 应用场景:执行一段代码,不管是否发生异常,都必须执行finally里面的程序。
-
throws
-
基本介绍
-
如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,表明该方法的调用者负责处理。
-
在方法声明中用 throws语句可以声明抛出异常的列表, throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
public void f2() throws FileNotFoundException,NullPointerException,ArithmeticException { //创建了一个文件流对象 //老韩解读: //1. 这里的异常是一个FileNotFoundException 编译异常 //2. 使用前面讲过的 try-catch-finally //3. 使用throws ,抛出异常, 让调用f2方法的调用者(方法)处理 //4. throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类 //5. throws 关键字后也可以是 异常列表, 即可以抛出多个异常 FileInputStream fis = new FileInputStream("d://aa.txt"); }
-
-
-
对于编译异常,程序中必须处理,比如try- catch或者 throws
-
对于运行时异常,程序中如果没有处理,默认就是 throws的方式处理举例
-
子类重写父类的方法时,对抛岀异常的规定:孑类重与的方法所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常的类型的子类型[举例]
class Father { //父类 public void method() throws RuntimeException {} } class Son extends Father {//子类 //3. 子类重写父类的方法时,对抛出异常的规定:子类重写的方法, // 所抛出的异常类型要么和父类抛出的异常一致,要么为父类抛出的异常类型的子类型 //4. 在throws 过程中,如果有方法 try-catch , 就相当于处理异常,就可以不必throws @Override public void method() throws ArithmeticException {} }
-
在 throws过程中,如果有方法try- catch,就相当于处理异常,就可以不必throws
-
0052 自定义异常
-
自定义异常的步骤
- 定义类:自定义异常类名(程序员自己写)继承
Exception
或RuntimeException
- 如果继承
Exception
,属于编译异常 - 如果继承
RuntimeException
,属于运行异常(一般来说,继承RuntimeException
) - 继承
RuntimeException
的好处- 我们可以使用默认的处理机制,而编译时异常则不可以(需要显示的处理)
- 定义类:自定义异常类名(程序员自己写)继承
-
//要求年龄在18~120,否则抛出一个异常
public class CustomException {
public static void main(String[] args) {
int age = 12;
//要求年龄在18~120,否则抛出一个异常
if(!(age>=18 && age<=120)){
throw new AgeException("年龄需要在18~120之间");
}
System.out.println("你的年龄正确");
}
}
//自定义的异常AgeException--运行时异常
class AgeException extends RuntimeException {
public AgeException(String message) {
super(message);
}
}
-
输出结果
-
throw和throws的区别
意义 位置 后面跟的东西 throws 异常处理的一种方式 方法声明处 异常的类型 throw 手动生成异常的关键字 方法体中 异常对象
0460