一、关键字:static
当我们编写一个类时,其实就是在描述其对象的属性和行为,而并没有产生实质上的对象,只有通过new关键字才会产生出对象,这时系统才会分配内存空间给对象,其方法才可以供外部调用。我们有时候希望无论是否产生对象或无论产生多少对象的情况下,某些特定的数据在内存空间里只有一份,例如所有的中国人都有个国家名称,每个中国人都共享这个国家名称,而不必在每个中国人的实例对象中都单独分配一个用于代表国家名称的变量
含义
使用
修饰属性(静态变量、类变量)
属性:按是否使用static修饰,又分为:静态属性、非静态属性(实例变量)
区别
实例变量
我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性(实例变量),当修改一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改
静态变量
我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,获取的是修改过的值
关于static修饰属性的其他说明
①静态变量随着类的加载而加载,可以通过”类.静态变量”进行调用
②静态变量的加载早于对象的创建
③由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法去的静态域中
④ 类变量 实例变量
类 yes no
对象 yes yes
静态属性举例
System.out;Math.PI
实例变量与类变量的内存结构
修饰方法(静态方法)
①随着类的加载而加载,可以通过”类.静态方法”的方式进行调用
② 静态方法 非静态方法
类 yes no
对象 yes yes
③静态方法中,只能调用静态的方法或属性;对于非静态方法中,既可以调用非静态的方法和属性,也可以调用静态的方法和属性
在静态的方法内,不能使用this关键字、super关键字!!
应用
属性是可以被多个对象可共享的,不会随着对象的不同而不同的
类中的常量也声明为static
操作静态属性的方法,通常设置为static的
工具类的方法,习惯上声明为static。比如:Math、Arrays、Collections等
二、main()的使用说明
定义
①main() 方法作为程旭的入口
②main() 方法也是一个普通的静态方法
③main() 方法可以作为我们与控制台交互的方式(之前使用Scanner)
三、类的结构:代码块(初始化块)
作用
结构
代码块如果有修饰的话,只能使用static
静态代码块(static {})
>内部可以有输出语句
>随着类的加载而执行
>可以初始化类的信息(初始化类变量)
>如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行
>静态代码块的执行要早于非静态代码块的执行
>静态代码块内只能调用静态的属性、静态的方法
非静态代码块({})
>内部可以有输出语句
>随着对象的创建而执行
>可以在创建对象时,对对象的属性等进行初始化
>如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行
>非静态代码块内可以调用静态的属性、静态的方法、非静态的属性、非静态的方法
对属性可以赋值的位置 ①默认初始化 ②显式初始化 ③构造器中初始化 ④有了对象后,可以通过”对象.属性”或”对象.方法”的方式,进行赋值 ⑤在代码块中赋值
使用场景
四、关键字:final
含义
使用
修饰类
此类不能够被其他类所继承
比如:String类、System类、StringBuffer类等
修饰方法
此方法不能够被重写
比如:Object类中 getClass()
修饰变量
此时的”变量”称为一个常量
①修饰属性
可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
②修饰局部变量
尤其是修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能再方法体内使用形参,但不能重新赋值
static final组合使用
只能用来修饰属性、方法
修饰属性:全局常量
修饰方法:该方法直接通过类来调用,并且不能被重写
五、关键字:abstract
定义
抽象的
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计的非常抽象,以至于它没有具体的实例,这样的类叫做抽象类
使用
可以用来修饰类、方法
修饰类
此类不能实例化
>抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程)
>开发中,都会提供抽象类的子类,让子类对象去实例化,以此来实现抽象类的功能修饰方法
抽象方法只有方法的声明,没有方法体
>包含抽象方法的类一定是抽象类。反之,抽象类中可以没有抽象方法
>若子类重写了父类中的所有的抽象方法后,此子类方可实例化;若子类没有重写父类中所有的抽象方法,该子类也是一个抽象类,需要使用 abstract 修饰
注意点
①abstract不能用来修饰属性、构造器、代码块等结构
②abstract不能用来修饰私有方法、静态方法、final的方法、final的类
使用场景
用于模型化那些父类无法确定全部实现,而是由其子类提供具体实现的对象的类
例如:设计模式——模板方法
匿名类
抽象类的匿名子类的使用
使用
六、关键字:interface
理解
一方面,有时必须从几个类中派生出一个子类,继承他们所有的属性和方法。但Java不支持多继承,有了接口,就可以得到多重继承的效果
Java中,接口与类是并列的两个结构
使用
体现多态性 接口实际上可以看作是一种规范 开发中,体会面向接口编程
①使用interface关键字定义接口
②组成成员
JDK7及以前
只能定义全局常量和抽象方法
>全局常量:public static final(书写时可以省略不写)
>抽象方法:public abstract
JDK8
除了全局常量和抽象方法之外,增加了定义静态方法、默认方法
>静态方法
接口中定义的静态方法,只能通过接口来调用。使用接口的实现类无法调用该静态方法
>默认方法
通过接口实现类的对象,可以调用接口中的默认方法
如果实现类重写了接口的默认方法,调用时,仍然调用的是重写的方法
如果子类(或实现类)继承的父类与实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参数的方法(类优先原则)
如果实现类实现了多个接口,而多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错(接口冲突),需要在实现类中重写该方法
如何在子类(或实现类)的方法中调用父类、接口被重写的方法:
class SubClass extends SuperClass implements CompareA {
public void method() {
System.out.println("SubClass");
}
public void myMethod() {
method(); //调用自己重写的方法
super.method(); //调用父类声明的方法
CompareA.super.method(); //调用接口的默认方法
}
}
class SuperClass {
public void method() {
System.out.println("SuperClass");
}
}
interface CompareA {
default void method() {
System.out.println("CompareA");
}
}
接口中不能定义构造器!意味着接口无法被实例化
③Java开发中,接口通过类去实现(implements)的方式来使用
如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
④Java类可以实现多个接口(接口的多实现)
格式:class A extends B implements C,D
弥补了单继承的局限性
匿名实现类
实现上与匿名子类相同
代理模式与工厂模式
代理模式
https://www.yuque.com/sp1bgo/vmn0df/zyvsti#GJgKp
工厂模式
https://www.yuque.com/sp1bgo/vmn0df/zyvsti#YFCcp
抽象类与接口有哪些异同
相同:不能实例化;都可以包含抽象方法
不同点:
抽象类,接口(java7,java8,java9)的定义、内部结构解释说明
类:单继承性
接口:多继承性
类和接口:多实现
七、类的结构:内部类(InnerClass)
定义
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类
Java中允许将一个类A声明在一个类B中,则类A就是内部类,类B就是外部类
分类
成员内部类(静态、非静态)
作为外部类的成员
调用外部类的结构(使用外部类.this.结构)
可以被static修饰
可以被四种权限修饰
作为类
类内可以定义属性、方法、构造器等
可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
可以被abstract修饰
实例化成员内部类的对象
//创建Dog实例(静态的成员内部类)
Person.Dog dog = new Person.Dog();
dog.show();
//创建Bird实例(非静态的成员内部类)
Person p = new Person();
Person.Bird bird = p.new Bird();
bird.sing();
成员内部类中区分调用外部类的结构
如果内部类与外部类无重名的情况,可以直接调用
如果有重名的情况
public void display(){
System.out.println(this.name); //自己的属性
System.out.println(Person.this.name); //外部类的属性
}
局部内部类(方法内、代码块内、构造器内)
使用
返回一个接口的实现类的对象
注意点
在局部内部类的方法中,如果调用局部内部类所声明的方法中的局部变量的话要求此局部变量声明为final
jdk7之前:要求此局部变量显式的声明为final
jdk8之后:可以省略final的声明
编译
成员内部类和局部内部类在编译之后都会生成字节码文件
成员内部类:外部类$内部类名.class
局部内部类:外部类$数组 内部类名.class