static关键字:
- 可用来修饰:属性、方法、代码块、内部类【都是随着类的加载而加载】
- 使用static修饰的属性:静态变量(类变量)
- 属性按是否使用static修饰,分为静态属性VS非静态属性(实例变量)
实例变量:创建了类的多个对象,每个对象独立拥有一套非静态属性,修改其中一个对象的非静态属性,不影响其他对象
静态变量:多个对象共享同一个静态变量,通过一个对象修改,其他对象调用此静态变量时是修改过的
- 其他说明
- 静态变量随着类的加载而加载【可通过类.静态变量的方式进行调用】
- 静态变量的加载早于对象的创建
- 由于类只会加载一次,所以静态变量在内存中也只会存在一份,存在方法去的静态域中
- 使用static修饰的方法:静态方法
- 可通过类.方法名调用
- 静态方法中,只能调用静态的方法或属性
非静态方法中,静态/非静态的方法或属性都可以
- 静态方法内,this,super关键字都不能用
- 开发中,如何确定一个属性是否要声明为static的?
属性可以被多个对象共享,不会随着对象的不同而不同
- 开发中,如何确定一个方法是否要声明为static的?
操作静态属性的方法通常为static
工具类中的方法,习惯声明为static。如:Math, Arrays
单例设计模式
采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例
实现:饿汉式VS懒汉式
饿汉式
class Bank{
private Bank(){
}
private static Bank instance = new Bank();
public static Bank getInstance(){
return instance;
}
}
懒汉式
class Order{
private Order(){
}
private static Order instance = null;
public static Order getInstance(){
if (instance == null)
instance = new Order();
return instance;
}
}
区分:
饿汉式:坏处:对象加载时间过长,一开始就要加载
好处:线程安全
懒汉式:好处:延迟对象的创建,要用的时候才创建
坏处:目前的写法线程并不安全
代码块
- 作用:用来初始化类、对象
- 代码块如果有修饰,只能用static
- 分类:静态代码块VS非静态代码块
- 静态代码块
>内部可写输出语句
>随着类的加载而运行
>作用:初始化类的信息(对静态属性进行重新赋值)
>若一个类中定义了多个代码块,按声明顺序先后执行
>静态代码块的执行优先于非静态代码块
>静态代码块只能调用静态属性、方法,不能调用非静态的结构
- 非静态代码块
>内部可写输出语句
>随着对象的创建而运行【每创建一个对象就执行一次】
>作用:可以在创建对象时,对对象的属性等进行初始化
>非静态代码块可以调用静态属性、方法以及非静态属性、方法
赋值先后顺序
- 默认初始化
- 显示初始化
- 构造器中初始化
- 创建对象后,通过“对象.属性”或“对象.方法”赋值
- 在代码块中赋值
优先级:1->2/5->3->4
final关键字
- 可用来修饰类、方法、变量
- 修饰一个类:此类不能被其他类继承,如String类、System类
- 修饰一个方法:此方法不能被重写
- 修饰变量:此时该变量变成一个常量,不能再进行赋值
- final修饰属性,可考虑的赋值位置有:显式初始化,代码块中,构造器初始化
- 局部变量:尤其是使用final修饰形参时,此形参是一个常量,调用此方法时,给常量形参赋一个值,之后只能在此方法体中使用该形参,不能重新赋值
static final 可修饰属性、方法
属性:全局常量
abstract关键字
可修饰类、方法
修饰类:抽象类
此类不能实例化
抽象类中一定有构造器,便于子类对象实例化时调用(涉及子类对象实例化全过程)
开发中,都会提供抽象类的子类,让子类对象实例化完成相关操作
修饰方法:抽象方法
只有方法的声明,没有方法体【public abstract void go();】
包含抽象方法的类一定是抽象类
若子类重写了父类中的所有抽象方法,此子类才能实例化
若没有全部重写,则子类也是一个抽象类
【注意点】
- 不能修饰属性、构造器
- 不能修饰私有方法、静态方法、final方法(不能被重写)、final的类(不能继承)
抽象类的匿名子类
method1(new student()); //匿名对象
Worker worker = new Worker();
method1(worker); //非匿名类的非匿名对象
method1(new Worker()); //非匿名类的匿名对象
//创建了一个匿名子类的非匿名对象
Person p = new Person(){
@Override
public void eat() {
super.eat();
}
};//方法体中把抽象方法全部重写/方法体中把抽象方法全部重写
//创建了一个匿名类的匿名对象
method1(new Person() {
@Override
public void eat() {
super.eat();
}
});
接口
- 使用interface定义
- 接口和类是并列的两个结构
- 如何定义接口:定义接口中的成员
- JDK7及以前,只能定义全局常量和抽象方法
> 全局常量:public static final的【可以省略不写,默认就是这样】
> 抽象方法:public abstract【可以省略不写,默认就是这样】
- JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
- 接口中不能定义构造器,即不可实例化
- 开发中,通过类实现(implement)接口的功能
- 如果实现类覆盖了接口中的所有抽象方法,则可以实例化
- 如果实现类没有覆盖接口中的所有抽象方法,则是抽象类,
- Java类可以实现多个接口
格式:class A extends B implements C,D,E
接口的使用:
接口的具体使用体现了多态性(可被多个类实现)
接口实际上可以看作是一种规范
public class USBTest {
public static void main(String[] args) {
Computer c = new Computer();
Flash flash = new Flash();
c.transferData(flash);
}
}
interface USB{
void start();
void stop();
}
class Computer{
public void transferData(USB usb){
usb.start();
usb.stop();
}
}
class Flash implements USB{
@Override
public void start() {
System.out.println("开始");
}
@Override
public void stop() {
System.out.println("停止");
}
}
【形参类型为接口的类型时,在实际调用时代入的是实现了该接口的类的对象】
//1.接口的非匿名实现类的非匿名对象
Flash flash = new Flash();
c.transferData(flash);
//2.接口的非匿名实现类的匿名对象
c.transferData(new Flash());
//3.接口的匿名实现类的非匿名对象
USB u = new USB() {
@Override
public void start() {
System.out.println("s");
}
@Override
public void stop() {
System.out.println("b");
}
};
//4.接口的匿名实现类的匿名对象
c.transferData(new USB() {
@Override
public void start() {
System.out.println("s");
}
@Override
public void stop() {
System.out.println("b");
}
});
代理模式
public class NetWorkTest {
public static void main(String[] args) {
Server server = new Server();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface NetWork{
void browse();
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work = work;
}
@Override
public void browse() {
check();
work.browse();
}
public void check(){
System.out.println("before work");
}
}
没有显式地用Server调用browse()方法,而是通过ProxyServer调用了Server中的browse()方法。【因为ProxyServer中可能还会在调用一些其他的方法,可以用这个类代理实现Server中要实现的方法】
应用场景
工厂模式
实现创建者和调用者的分离
JDK8中的接口:
除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
- 接口中定义的静态方法,只能通过接口进行调用【接口.方法】
- 通过实现类的对象,可以调用接口中的默认方法(如果实现类重写了接口中的默认方法,调用时仍然是调用重写的方法)
- 如果子类(或实现类)继承的父类和实现的接口声明了同名同参的方法,那么在子类没有重写该方法的情况下,默认调用的是父类中的方法à类优先原则
- 如果实现类实现了多个接口,而这些接口中定义了同名同参的方法,则在子类没有重写该方法的情况下,会报错à接口冲突【所以必须要重写该方法】
-
public void myMethod(){ //调用自己定义的重写方法 method3(); //调用父类中声明的 super.method3(); //调用接口中定义的默认方法 CompareA.super.method3(); }
内部类
- 将一个类A声明在另一个类B中,则A为内部类,B为外部类
- 分类:成员内部类VS局部内部类(方法内、代码块内、构造器内)
- 成员内部类:
一方面,作为外部类的成员
- 调用外部类的结构【调用外部类的方法时:外部类名.this.方法名】
- 可以被static修饰
- 可被四种不同的权限修饰符修饰
另一方面,作为一个类
- 类内可以定义属性、方法、构造器等
- 可以被final修饰,表示不能被继承;不用final就可以被继承
- 可以被abstract修饰
- 1)如何实例化成员内部类的对象
2)如何在成员内部类中区分外部类的结构
3)开发中局部内部类的使用
//创建静态内部类
Person.Dog dog = new Person.Dog();
//创建非静态内部类
Person p = new Person();
Person.Bird bird = p.new Bird();
在局部内部类的方法中,如果如果调用局部内部类所声明的方法中的局部变量,要求此局部变量声明为final的