(六)java的static、final、单例模式、接口和匿名内部类

1. static

  • 使用范围:可用static修饰属性,方法,代码块,内部类
  • 被修饰后的成员具备以下特点:
    • 随着类的加载而加载
    • 优先于对象存在
    • 修饰的成员,被所有对象所共享
    • 访问权限允许时,可不创建对象,直接被类调用
  • 方法,类中使用static修饰的方法
    • 没有对象的实例时,可以用类名.方法名()的形式访问由static 修饰的类方法
    • 在static方法内部只能访问类的static修饰的属性或方法,不能访问类的非static的结构
    • 因为不需要实例就可以访问static方法,因此static方法内部不能有this和super
    • static修饰的方法不能被重写
//探究static的使用和准则
public class Chinese {
    private String name;
    private int age;
    public static String nation = "大中国";//静态变量
    public void f1(){
        System.out.println("f1()");
    }
    public static void f2(){
        System.out.println("f2()");
    }
    public static void show(){
        System.out.println("自我介绍" + nation);
        f2();
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}//测试部分:
public class Test1 {
    public static void main(String[] args) {
        Chinese malong = new Chinese();
        malong.setAge(32);
        malong.setName("马龙");
        malong.nation = "中华人民共和国";
        Chinese yaoming  = new Chinese();
        yaoming.setAge(34);
        yaoming.setName("姚明");
        yaoming.nation = "中国";
        System.out.println(malong.getName());
        System.out.println(malong.nation);//一般不这么用,静态方法直接使用:类名 + 成员名
        System.out.println(Chinese.nation);
        Chinese.show();//静态方法
    }
}

1.1 static的流程图

请添加图片描述

2. 单例模式

单例模式:要求程序中某一组件,在程序运行的整个生命周期中,只有一个实例
单例模式有两种:饿汉式,懒汉式
步骤如下:

  • 构造函数私有化,外面的组件不能主动创建这个对象
  • 提供静态方法返回对象实例,返回的是静态实例,所以只有一个实例

2.1 饿汉式

  • 好处:线程安全
  • 坏处:加载时,时间比较长

2.2 懒汉式

存在线程安全问题,没有静态初始化

饿汉式://探究单例模式
public class HungerSingleton {
    private HungerSingleton() {//构造函数私有化
        System.out.println("HungerSingleton初始化...");
    }
    private static HungerSingleton instance = new HungerSingleton();//在方法区新建一个对象
    public static HungerSingleton getInstance() {//静态方法,返回实例对象
        return instance;
    }
}
  懒汉式:
public class LazySingleton {
    private LazySingleton() {//构造函数私有化
        System.out.println("LazySingleton被调用...");
    }
    private static LazySingleton instance = null;//实例对象先设为空,如果要使用在new
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}
测试部分
public class Test1 {
    public static void main(String[] args) {
        //饿汉式
        HungerSingleton s1 = HungerSingleton.getInstance();//调用HungerSingleton的静态方法getInstance
        HungerSingleton s2 = HungerSingleton.getInstance();
        HungerSingleton s3 = HungerSingleton.getInstance();

        //懒汉式:在方法区懒得初始化,所以叫懒汉式
        LazySingleton n1 = LazySingleton.getInstance();//调用LazySingleton的静态方法getInstance
        LazySingleton n2 = LazySingleton.getInstance();
        LazySingleton n3 = LazySingleton.getInstance();
    }
}

2.3 饿汉式JMM状态

请添加图片描述

3. 代码化和初始化顺序

顺序:

  • 静态初始化(先进行父类的初始化,再进行子类初始化)
  • 父类代码块初始化、构造函数
  • 子类代码块初始化、构造函数
//探究代码块和初始化顺序
public class Paent {
    public int i = 10;//初始化
    {//代码块
        System.out.println("parent初始化代码块1");
    }
    {//代码块
        System.out.println("parent初始化代码块2");
    }

    public static int i2 = 0;//静态初始化
    static{//静态代码块
        System.out.println("parent静态初始化代码块1");
    }
    static{//静态代码块
        System.out.println("parent静态初始化代码块2");
    }

    public Paent() {
        System.out.println("parent构造函数。。。");
    }
}

/*初始化顺序
1.静态初始化
2,初始化代码、构造函数。
如果有父类,先进行 父类静态-->子类静态 -->父类初始化代码块、构造函数-->子类初始化代码块、构造函数
 */
public class Children extends Paent {
    public int i = 20;
    {//代码块
        System.out.println("Children初始化代码块1");
    }
    
    {//代码块
        System.out.println("Children初始化代码块2");
    }
    static{//静态代码块
        System.out.println("Children静态初始化代码块1");
    }
    static{//静态代码块
        System.out.println("Children静态初始化代码块2");
    }

    public Children() {
        System.out.println("Children构造函数。。。");
    }

    public static void main(String[] args) {
        Children children = new Children();
    }
}

4. final关键字

  • 修饰类:表示类不能被继承
  • 修饰方法:表示方法不能被重写
  • 修饰成员变量:表示变量不能被改变
//探究关键词final
public class Test {
    public static void main(String[] args) {
    }
}

class A {      //final修饰的类不能被继承
//    public final void f1(){};  //final修饰的方法不能被重写
    public void f1() {
    }
}

class B extends A {
    public final int i = 1;
    @Override
    public void f1() {
//        i = 20;      //final修饰的属性不能被改变
    }
}

5. 抽象类

  1. abstract关键字来修饰一个类,这个类叫做抽象类。
  2. 用abstract来修饰一个方法,该方法叫做抽象方法。抽象方法:只有方法的声明,没有方法的实现。如public abstratc void talk();注意没有大括号
  3. 含有抽象方法的类必须声明为抽象类
  4. 抽象类不能被实例化,只能用来继承,子类重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类
//探究抽象类的特性
public abstract class A {//声明抽象类
    public abstract void f1();//抽象方法
    public void f2() {//抽象类中可以写非抽象的方法
        System.out.println("这是一个f2()方法。。。");
    }
}
public class B extends A {
    @Override
    public void f1(){//实现抽象类中的抽象方法
        System.out.println("实现抽象类的f1()方法。。。");
    }
}
//测试
public class Test {
    public static void main(String[] args) {
//        new A();//不能实例化抽象类
        B b = new B();//实例化抽象类的子类实现父类的抽象方法
    }
}

6. 接口

  • 有了接口, 就可以得到多重继承的效果。
  • 它们之间又没有is-a的关系,但是具有相同的行为特征。例如:鼠标、键盘、打印机、扫描仪、摄像头、充电器、 MP3机、手机、数码相机、移动硬盘等都支持USB连接。
  • 继承是一个"是不是"的关系,而接口实现则是 "能不能"的关系。
public interface Usb {
    //接口方法默认有public abstract
    public void start();
    public void end();
    //接口中不能有非抽象方法,只能存在抽象方法
//    public void f1(){};  报错
}
public interface TypeC {
    void transfer();
}
public class Printer implements Usb, TypeC {//接口能实现多继承,抽象类不能
    @Override
    public void transfer() {
        System.out.println("TypeC接口传输数据");
    }
    @Override
    public void start() {
        System.out.println("Usb接口启动");
    }
    @Override
    public void end() {
        System.out.println("Usb接口关闭");
    }
}

6.1 接口与抽象类

  • 抽象类可以有非抽象方法,接口只能有抽象方法
  • 接口中方法默认带public abstract
  • 接口可以实现多继承,抽象类不可以

7. 内部类(了解)

将一个类放在另一个类的内部,这个类就叫做内部类
内部类的分类:

  • 成员变量的位置
    • static成员内部类
    • 非静态的成员内部类
  • 方法中的某个位置:局部内部类

语法:

  • 修饰成员变量的所有的修饰符都可以修饰成员内部类
  • 部类可以使用继承
//探究内部类的使用
public class Test {
    public static void main(String[] args) {
        //创建静态属性内部类的方法
        Person.Dog dog = new Person.Dog();
        dog.eat();
        //创建非静态属性内部类的方法
        Person p = new Person();
        Person.Cat cat = p.new Cat();
        cat.eat();
        //成员方法中定义的局部内部类
        p.f1();
    }
}
public class Person {
    private String name;
    private int age;

    //内部类,如果一个类只给当前的类使用,其他的类无法使用,比如Dog 和Cat类只能在Person中使用
    //静态内部类
    public static class Dog {
        public void eat() {
            System.out.println("狗吃骨头");
        }
    }
    public class Cat {//内部类
        public void eat() {
            System.out.println("猫吃鱼");
        }
    }
    public void f1() {//局部内部类
        class Bird {
            public void eat() {
                System.out.println("鸟吃虫子");
            }
        }
        Bird bird = new Bird();
        bird.eat();
    }
}

8. 匿名内部类

  • 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。
  • 匿名内部类的特点
    • 匿名内部类必须继承父类或实现接口
    • 匿名内部类只能有一个对象
    • 匿名内部类对象只能在使用多态形式引用
语法:
接口 变量名 =  new 接口 {
	重写的代码
}

案例如下:

package test8;//探究匿名内部类的使用和原则

public class Test {
    public static void f1(Usb usb) {
        usb.start();
        usb.end();
    }
    public static void f2(TypeC typeC) {
        typeC.transfer();
    }
    public static void main(String[] args) {
        //方法1:
        /*
        1.多态性:编译类型时父类
        2.new接口,后面跟一个实现
        3.有一个对象usb1,实现了Usb接口的一个没有名字的类的实例
         */
        Usb usb1 = new Usb() {
            @Override
            public void start() {
                System.out.println("打印机Usb启动");
            }
            @Override
            public void end() {
                System.out.println("打印机Usb关闭");
            }
        };
        f1(usb1);
        //方法2:匿名内部类直接作为方法的参数
        f2(new TypeC() {
            @Override
            public void transfer() {
                System.out.println("苹果14正在传输数据...");
            }
        });
    }
}
public interface TypeC {
    void transfer();
}
public interface Usb {
    //接口方法默认有public abstract
    public void start();
    public void end();
    //接口中不能有非抽象方法,只能存在抽象方法
//    public void f1(){};  报错
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值