类变量和方法
类变量
- 类变量:静态变量,被同一个类的所有对象共享,可以通过类名访问
- 在类加载的时候就生成了
定义方法
-
定义语法:
访问修饰符 static 数据类型 属性名
-
访问语法:
类名.类变量名
对象名.类变量名
。访问修饰符的使用权限和普通变量一样 -
jdk8以前认为是在方法区,加载类信息的时候加载;jdk8以后认为是在堆里面,class实例的尾部
使用场景
- 需要让某个类的所有类都共享一个变量时
类变量与实例变量
- 类变量被所有成员共享,实例变量是每个对象独享;类变量不用new对象就能使用
- 类变量访问:
类名.类变量名
;实例对象访问:对象名.变量名
- 类变量在类加载时生成;实例变量在对象创建时生成
- 类变量生命周期随着类的加载开始,类的消亡而销毁;实例变量伴随对象生成、销毁。
类方法
- 类方法也叫静态方法;
定义调用
定义
访问修饰符 static 数据返回类型 方法名(){} //推荐
static 访问修饰符 数据返回类型 方法名(){}
调用
类名.类方法名();
对象名.类方法名();
使用场景
- 当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法,提高开发效率;例如工具类
类方法和普通方法
- 类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区;
- 类方法中不能使用
this
、super
关键字;普通方法中可以使用this
、super
关键字;(方法重写也不能用super) - 类方法通过类名或对象名调用;普通方法只能用对象名调用;
- 类方法中只能访问类变量或者类方法;普通方法既可以访问普通方法(变量),也可以放访问类方法(变量);
main方法语法
public static void main(String[] args){ }
-
main方法是由java虚拟机调用的
-
public:调用main方法是跨类跨包调用了,所以权限是
public
; -
static:虚拟机在执行main( )时不必创建对象,所以方法是静态方法;
-
void: main( )方法没有返回值;
-
String[] args:main( )方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行类的参数
特别说明
- 在main方法中,可以直接调用本类中的静态方法(变量);不能直接访问本类的非静态变量(方法),需要创建对象访问
代码块
- 又称初始代码块,属于类的一部分,类似于方法,将逻辑语句封装在方法块中,通过{}包围起来
- 没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显示调用,而是加载类时,或创建对象时隐式调用
- 不管有几个构造器,不管调用哪个构造器,代码块里面的内容会优先于构造器调用
- 使用场景:多个构造器有重复的语句,可以抽取到代码块中,提高代码的重用性
基本语法
[修饰符]{
代码
};
注意事项
- 访问修饰符可以不写,只能写static;
- 代码块分为静态代码块和普通代码块;
- 逻辑语句可以写任何语句
- 最后的分号可以不写
静态代码块与普通代码块
- 静态代码块作用是对类进行初始化,随着类的加载而执行,并且只会执行一次。普通代码块每创建一个对象就会执行一次
- 类什么时候被加载? (背下来)
- 创建对象实例时
- 创建子类对象实例,父类也会加载;先加载父类后加载子类
- 使用类的静态成员时(静态属性、静态方法)
- 普通代码块在创建对象实例时执行。使用类的静态成员不会执行普通代码块
- 构造器的最前面隐藏了
super()
和普通代码块,静态代码块和静态属性在类加载时执行,因此是优先于构造器和普通代码块执行的 - 静态代码块只能直接调用静态成员,普通代码块可以调用任意成员
创建一个对象时,在一个类的调用顺序※※
1、静态代码块和静态属性初始化
- 静态代码块和静态属性优先级一样,谁写在前面谁就先调用
2、普通代码块和普通属性的初始化
- 普通代码块和普通属性优先级一样,谁写在前面谁就先调用
3、构造函数
创建子类对象时调用顺序※※※
1、父类的静态代码块和静态属性(优先级一样,按定义顺序执行);
2、子类的静态代码块和静态属性(优先级一样,按定义顺序执行);
3、调用父类构造器前,会先执行父类的普通代码块和普通属性(优先级一样,按定义顺序执行)
4、父类的构造器
5、调用子类构造器前,会先执行子类的普通代码块和普通属性(优先级一样,按定义顺序执行)
6、子类的构造器
单例设计模式
- 什么是设计模式:在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的方式
- 单例模式:采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
饿汉模式
- 创建了对象可能没有使用,会造成浪费
实现步骤
1、私有化构造方法,防止直接new
2、在类的内部创建对象
3、向外部暴露一个 静态的公共方法 getInstance
4、代码实现
class SingleOne{
private string name;
//1、将构造器初始化
private SingleOne(String name){
}
//2、在类的内部创建对象,为了下面静态方法调用,这里对象也要static
//只要类被加载,没有使用也会创建这个实例,所以就叫饿汉
private static SingleOne so = new SingleOne("singleone");
//3、静态的公共对象,返回so对象
public static SingleOne getInstance(){
return so;
}
}
懒汉模式
class Cat{
private String name;
private static Cat cat;
private Cat(String name){
this.name = name
}
public static Cat getInstance(){
//调用这个方法,cat为空时才会创建,不会造成资源浪费
//后面再次调用会返回上次创建的对象
if(cat == null){
cat = new Cat("小花花");
}
return cat;
}
}
饿汉式与懒汉式
- 最主要的区别是创建对象的时机不同:饿汉式是在类加载的时候创建对象实例,懒汉式是在使用时创建(调用getInstance方法时);
- 饿汉式不存在线程安全问题;懒汉式存在线程安全问题;
- 饿汉式存在资源浪费的可能,懒汉式则不存在;
- java.lang.Runtime就是经典的单例模式
final关键字
- 可以修饰类、属性、方法、局部变量
- 修饰类,不能被继承
- 修饰方法,不能被子类覆盖/重写
- 修饰属性,值不能被修改
- 修饰局部变量,值不能被修改
注意事项
-
final
修饰的属性又叫常量,一般用XX_XX来命名 -
final
修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一:- 定义时
- 构造器中
- 代码块中
-
如果修饰静态属性,则只能在定义时和静态代码块中赋值,不能在构造器中赋值
-
final类不能继承,可以实例化对象
-
如果不是final类,但是含有final方法,则该方法不能被重写,但是可以继承
-
final不能修饰构造器
-
final和static往往搭配使用效率更高,不会导致类加载(下面的程序不会输出静态代码块执行)
-
包装类(Integer、Boolean)、String类是final类,不能继承
抽象类
-
当父类的一些方法不能确定时,可以用
abstract
关键字来修饰该方法,这个方法就是抽象类,用abstract
来修饰该类就是抽象类 -
访问修饰符 abstract 类名{} 访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
使用细节
- 抽象类不能被实例化
- 抽象类不一定包含抽象方法,还可以有实现的方法;
- 包含抽象方法一定是抽象类
abstract
只能修饰类和方法,不能修饰属性和其他的- 抽象类可以有任意成员,比如非抽象方法、构造器、静态属性
- 如果一个类继承了抽象类,则他必须实现(有方法体就算实现了)抽象类的所有方法,除非他自己也声明为抽象类
- 抽象方法不能使用
private
、final
、static
来修饰,因为这些关键字都是和重写相违背的
模板设计模式
接口
- 接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来
定义
interface 接口名{
//属性
//方法(1、抽象方法;2、默认实现方法;3、静态方法)
}
class 类名 implements 接口{
自己的属性;
自己的方法;
必须实现的接口的抽象方法;
}
使用细节
-
接口不能被实例化 ;抽象类也不能被实例化
-
接口中的属性都是
public static final
,定义时必须初始化;访问方式是接口名.属性名
-
接口中的方法都会隐式地指定为
public abstract
方法 -
一个普通类实现接口,就必须将该接口的所有类都实现
-
抽象类实现接口时可以不实现接口的方法。
-
一个类可以实现多个接口;一个类只能直接继承一个类
class A implements IB,IC{}
-
接口不能继承其他的类,但是可以继承多个其他的接口
interface A extends B,C{}
-
接口的修饰符只能是public 和默认,类也是这样
-
接口中的方法必须都是抽象方法
实现接口与继承类
- 当子类继承了父类,就自动拥有父类的功能;如果子类需要扩展功能,可以用过实现接口来实现。接口是对java单继承模式的一种补充
- 解决的问题不一样
- 继承的价值在于解决代码的复用性和可维护性
- 接口的价值在于设计好各种规范,让其他类去实现这些方法
接口的多态特性
-
接口的引用可以指向实现了接口的类的对象
-
多态数组
-
多态传递现象
接口与抽象类的的区别
语法上的区别
- 抽象类有已经实现的方法;接口只存在
public abstract
方法 - 抽象类的成员属性可以是各种类型的,而接口中的成员变量只能是
public static final
类型的 - 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口
设计层面的区别
- 抽象类是对事物的抽象,接口是对行为的抽象
内部类
-
**类的五大成员:**属性、方法、构造器、代码块、内部类
-
一个类的内部又完整的嵌套了另一个类的结构。被嵌套的类称为内部类,嵌套其他类的类称为外部类
-
**内部类的最大特点:**可以直接访问私有属性,并且可以体现类与类之间的包含关系
-
分类:
- 定义在外部类局部位置上:
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点)
- 定义在外部类的成员位置上:
- 成员内部类(没有
static
修饰) - 静态内部类(有
static
修饰)
- 成员内部类(没有
- 定义在外部类局部位置上:
基本语法
class outer{//外部类
class inner{//内部类
}
}
class otherouter{
//外部其他类
}
局部内部类
- **定义位置:**定义在外部类的局部位置,比如方法中,有类名
- 局部内部类可以直接访问外部类的所有成员,包括私有成员
- 局部内部类不能添加访问修饰符,因为他就是一个局部变量。局部变量是不能使用访问修饰符的。
- 局部内部类可以使用
final
关键字。因为局部变量也可以使用final
- 作用域:仅仅在定义它的方法和代码块中
- 访问方式:
- 局部内部类访问外部类的成员:直接访问
- 外部类访问局部内部类:创建内部类对象,再访问
- 外部其他类不能访问局部内部类
- 如果外部类和局部内部类的对象重名时,默认遵循就近原则;如果想访问外部类的同名成员,使用
外部类名.this.成员
去访问。(外部类名.this本质上就是外部类的对象)
匿名内部类(重要)
-
特点
- 本质是一个类
- 是一个内部类
- 没有名字
- 是一个对象
-
基本语法
new 类或接口( 参数列表){ 类体 };
-
基于接口的匿名内部类:匿名内部类实现了接口
-
基于类的匿名内部类:匿名内部类继承了父类,重写了父类的方法
tiger的编译类型:IA接口
tiger的运行类型:匿名内部类,看不到名字,但是系统会自动分配一个名字
jdk在底层创建匿名内部类Outer04$1,立马就创建了Outer04$1实例,并把地址返回给tiger
匿名内部类只能使用一次,但是引用可以反复使用
IA tiger = new IA(){
public void cry(){
System.out.println("老虎叫");
}
}
interface IA{
public void cry();
}
注意事项
- 调用匿名内部类的方法有两种方式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2sZTB8j9-1623685587365)(C:\Users\stati\AppData\Roaming\Typora\typora-user-images\image-20210610230458861.png)]
- 可以访问外部类的所有成员,包括私有的
- 不能添加访问修饰符,因为他是一个局部变量
- 作用域:仅仅在定义它的方法和代码块中
- 访问方式:
- 局部内部类访问外部类的成员:直接访问
- 外部类访问局部内部类:创建内部类对象,再访问
- 外部其他类不能访问局部内部类
- 如果外部类和局部内部类的对象重名时,默认遵循就近原则;如果想访问外部类的同名成员,使用
外部类名.this.成员
去访问。(外部类名.this本质上就是外部类的对象)
实践案例
- 当做实参直接传递,简洁高效
interface AA{
public void cry();
}
main方法中
public static void show(AA a){
a.cry();
}
show (new AA(){
public void cry(){
Systme.out.println("AA cry");
}
});
成员内部类
-
成员内部类是定义在外部类的成员位置,并且没有
static
修饰 -
可以访问外部类的所有成员,包括私有的
-
可以添加任意访问修饰符,因为他的地位就是一个成员
-
作用域:和外部类的其他成员一样,为整个类体
-
访问方式:
-
成员内部类访问外部类成员:直接访问
-
外部类访问成员内部类:创建对象再访问
-
外部其他类访问成员内部类:(三种方式)
-
外部类的对象实例.new 内部类名(); (把new 内部类当做成员)
-
在外部类编写一个方法,返回一个成员内部类实例
-
-
-
如果外部类和局部内部类的对象重名时,默认遵循就近原则;如果想访问外部类的同名成员,使用
外部类名.this.成员
去访问。(外部类名.this本质上就是外部类的对象)
静态内部类
-
成员内部类是定义在外部类的成员位置,并且没有
static
修饰 -
可以访问外部类的静态成员,包括私有的;不能访问非静态成员
-
可以添加任意访问修饰符,因为他的地位就是一个成员
-
作用域:和外部类的其他成员一样,为整个类体
-
访问方式:
- 成员内部类访问外部类成员:直接访问静态成员
- 外部类访问成员内部类:创建对象再访问
- 外部其他类访问成员内部类:
- 因为是静态内部类,所以可以直接通过类名访问(满足访问权限)
- 编写一个方法,返回静态内部类的实例
-
如果外部类和局部内部类的对象重名时,默认遵循就近原则;如果想访问外部类的同名成员,使用
外部类名.成员
去访问。(因为都是静态的 不用this)