javse(2023/11/17)

1、单例模式(static实践)

所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某
个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法

步骤

  • 构造器私有化=》防止直接new
  • 类的内部创建对象
  • 向外暴露一个静态的公共方法。

饿汉式和懒汉式区别

  • 二者最主要的区别在于创建对象的时机不同:饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建
  • 饿汉式不存在线程安全问题,懒汉式存在线程安全问题
  • 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题
  • 在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式

饿汉式

package zhh.chapter09.single;

/**
 * 单例模式
 * 饿汉式
 * 用不用的着都创建此对象
 */
public class Single01 {
    public static void main(String[] args) {
        GirdFriend girdFriend1 = GirdFriend.getInstance();
        System.out.println(girdFriend1); //GirdFriend{name='小红'}

        GirdFriend girdFriend2 = GirdFriend.getInstance();
        System.out.println(girdFriend2);//GirdFriend{name='小红'},可以看出来一样

        System.out.println(girdFriend1==girdFriend2);//true


    }
}
class GirdFriend{
    //步骤[单例模式-饿汉式]
    //1. 将构造器私有化
    //2. 在类的内部直接创建对象(该对象是 static)
    //3. 提供一个公共的 static 方法,返回 gf 对象
    private String name;
    private static GirdFriend girdFriend=new GirdFriend("小红");

    private GirdFriend(String name) {
        this.name = name;
    }
    public static GirdFriend getInstance(){
        return girdFriend;
    }

    @Override
    public String toString() {
        return "GirdFriend{" +
                "name='" + name + '\'' +
                '}';
    }
}

 懒汉式

package zhh.chapter09.single;

/**
 * 单例模式
 * 懒汉式
 * 用的时候再创建此对象
 */
public class Single02 {
    public static void main(String[] args) {
        Cat cat1 = Cat.getInstance();
        System.out.println(cat1);//Cat{name='汤姆'}

        Cat cat2 = Cat.getInstance();
        System.out.println(cat2);//Cat{name='汤姆'}

        System.out.println(cat1==cat2);//true

    }

}
class Cat{
    //1.仍然構造器私有化
    //2.定義一個 static 靜態屬性對象
    //3.提供一個 public 的 static 方法,可以返回一個 Cat 對象
    //4.懶漢式,只有當用戶使用 getInstance 時,才返回 cat 對象,
    // 後面再次調用時,會返回上次創建的 cat 對象,從而保證了單例
    private String name;
    private static Cat cat;

    private Cat(String name) {
        this.name = name;
    }
    public static Cat getInstance(){
        if(cat==null){
            cat=new Cat("汤姆");
        }
        return cat;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + '\'' +
                '}';
    }
}

2、final关键字


final可以修饰类、属性、方法和局部变量.
使用场景

  • 当不希望类被继承时,可以用final修饰.
  • 当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰。
  • 当不希望类的的某个属性的值被修改,可以用final修饰.
  • 当不希望某个局部变量被修改,可以使用final修饰
     

final修饰属性必须初始化,final修饰的普通属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一

  • 定义时:如public final double TAX_RATE=0.08;
  • 在构造器中
  • 在代码块中

如果final修饰的属性是静态的,则初始化的位置只能是

  • 定义时
  • 在静态代码块,不能在构造器中赋值

注意事项

  1. final修饰的属性又叫常量,一般用XX_XX_XX来命名
  2. final类不能继承,但是可以实例化对象。
  3. 如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。
  4. 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。(都没子类的何谈重写)
  5. final不能修饰构造方法(即构造器)
  6. 包装类(Integer,Double,Float,Boolean等都是final),String也是final类。
  7. final和static往往搭配使用,效率更高,不会导致类加载.底层编译器做了优化处理。
package zhh.chapter09;

public class ExerChapter09 {

    public static void main(String[] args) {
        System.out.println(A.a);//只输出1
    }
}

class A {
    public final static int a=1;
    static{
        System.out.println("类被加载!");
    }
}

 3、抽象类

 当父类的某些方法,需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类

介绍

  • 用abstract关键字来修饰一个类时,这个类就叫抽象类:   访问修饰符  abstract  类名{}
  • 用abstract关键字来修饰一个方法时,这个方法就是抽象方法:   访问修饰符  abstract  返回类型方法名(参数列表); //没有方法体{}
  • 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类
     

 注意事项

  1. 抽象类不能被实例化
  2. 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法
  3. 一旦类包含了abstract方法,则这个类必须声明为abstract
  4. abstract只能修饰类和方法,不能修饰属性和其它的
  5. 抽象类可以有任意成员【抽象类本质还是类】,比如:非抽象方法、构造器、静态属性等等
  6. 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
     

 4、模板设计模式(实践抽象类)

基本介绍
抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。


模板设计模式能解决的问题

  • 当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
  • 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式

 实践

package zhh.chapter09.template;

public class TestTemplate {
    public static void main(String[] args) {
        AA aa = new AA();
        aa.timeCalculation(); //3
        BB bb = new BB();
        bb.timeCalculation(); //3
    }
}
package zhh.chapter09.template;

abstract public class Template {
    public abstract void job();
    public void timeCalculation(){
        long start = System.currentTimeMillis();
        job(); //多态的动态绑定,当子类对象运行这个方法时,运行子类的job()
        long end = System.currentTimeMillis();
        System.out.println(end-start);
    }
}

class AA extends Template{
    @Override
    public void job() {
        long num=0;
        for (int i = 0; i < 1000000; i++) {
            num+=i;
        }
    }
}

class BB extends Template{
    @Override
    public void job() {
        long num=0;
        for (int i = 0; i < 1000000; i++) {
            num+=i*i;
        }
    }
}

 5、接口

接口是更加抽象的抽象的类,抽象类里的方法可以有方法体,接口里的所有方法都没有方法体【jdk7.0及以下】。接口体现了程序设计的多态和高内聚低偶合的设计思想。
特别说明:Jdk8.0后接口类可以有静态方法,默认方法,也就是说接口中可以有方法的具体实现

注意事项

  • 接口不能被实例化,但可以指向实现此接口的对象实例(多态)
  • 接口中所有的方法是 public方法,接口中抽象方法,可以不用abstract修饰
  • 一个普通类实现接口,就必须将该接口的所有方法都实现。可以使用 alt+insert 来解决
  • 抽象类实现接口,可以不用实现接口的方法
  • 一个类同时可以实现多个接口: class Pig implements IB,IC)
  • 接口中的属性,只能是final的,而且是 public static final修饰符。比如:int a=1;实际上是public static final int a=1;(必须初始化)
  • 接口中属性的访问形式:接口名.属性名
  • 接口不能继承其它的类,但是可以继承多个别的接口:interface A extends B,CO
  • 接口的修饰符只能是public 和默认,这点和类的修饰符是一样的。
     

接口和继承类的区别联系

接口和继承解决的问题不同

  • 继承的价值主要在于:解决代码的复用性和可维护性。
  • 接口的价值主要在于:设计,设计好各种规范(方法),让其它类去实现这些方法。即更加的灵活..

接口比继承更加灵活

  • 接口比继承更加灵活,继承是满足is - a的关系,
  • 接口只需满足like - a的关系。接口在一定程度上实现代码解耦[即:接口规范性+动态绑定机制]

接口的多态

  • 多态参数
  • 多态数组
  • 接口存在多态传递现象
     

package zhh.chapter09.interface_;

public class InterfacePolyParameter {
    public static void main(String[] args) {
        //接口的多态体现
        //接口类型的变量 if01 可以指向 实现了 IF 接口类的对象实例
        //类似于类的上下转型
        IF if01 = new Monster();
        if01 = new Car();

        //继承体现的多态
        //父类类型的变量 a 可以指向 继承 AAA 的子类的对象实例
        //上下转型
        AAA a = new BBB();
        a = new CCC();
    }
}

interface IF {}
class Monster implements IF{}
class Car implements IF{}

class AAA { }
class BBB extends AAA {}
class CCC extends AAA {}
package zhh.chapter09.interface_;

public class InterfacePolyArr {
    public static void main(String[] args) {
        //多态数组 -> 接口类型数组
        Usb[] usbs = new Usb[2];
        usbs[0] = new Phone_();
        usbs[1] = new Camera_();
        /*
        给 Usb 数组中,存放 Phone 和 相机对象,Phone 类还有一个特有的方法 call(),
        请遍历 Usb 数组,如果是 Phone 对象,除了调用 Usb 接口定义的方法外,
        还需要调用 Phone 特有方法 call
        */
        for(int i = 0; i < usbs.length; i++) {
            usbs[i].work();//动态绑定.. //和前面一样,我们仍然需要进行类型的向下转型
            if(usbs[i] instanceof Phone_) {//判断他的运行类型是 Phone_
                ((Phone_) usbs[i]).call();
            }
        }
    }
}
interface Usb{
    void work();
}

class Phone_ implements Usb {
    public void call() {
        System.out.println("手机可以打电话...");
    }
    @Override
    public void work() {
        System.out.println("手机工作中...");
    }
}

class Camera_ implements Usb {

    @Override
    public void work() {
        System.out.println("相机工作中...");
    }
}
package zhh.chapter09.interface_;

/**
 * 演示多态传递现象
 */
public class InterfacePolyPass {
    public static void main(String[] args) {
        //接口类型的变量可以指向,实现了该接口的类的对象实例
        IG ig = new Teacher();
        //如果 IG 继承了 IH 接口,而 Teacher 类实现了 IG 接口
        //那么,实际上就相当于 Teacher 类也实现了 IH 接口.
        // 这就是所谓的 接口多态传递现象.
        IH ih = new Teacher();
    }
}
interface IH {
    void hi();
}

interface IG extends IH{ }
class Teacher implements IG {
    @Override
    public void hi() {
    }
}

6、内部类

基本介绍

一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员【思考:类的五大成员是哪些?[属性、方法、构造器、代码块、内部类]】,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系

四种内部类

  • 定义在局部位置(方法中/代码块):(1)局部内部类(2)匿名内部类
  • 定义在成员位置1)成员内部类(2)静态内部类

语法

class outer {//外部类
    class inner{}//内部类
}
class other{}//外部其他类

局部内部类

说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。

  1. 可以直接访问外部类的所有成员,包含私有的
  2. 不能添加访问修饰符,因为它的地位就是一个局部变量(本质还是一个类)。局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
  3. 作用域:仅仅在定义它的方法或代码块中。
  4. 局部内部类---访问---->外部类的成员【访问方式:直接访问】
  5. 外部类---访问---->局部内部类的成员【访问方式:创建对象,再访问(注意:必须在作用域内)】
  6. 外部其他类---不能访问----->局部内部类(因为局部内部类地位是一个局部变量)
  7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
package zhh.chapter09.innerclass;

/**
 * 局部内部类的使用
 * 定义在外部类的局部位置,比如方法中,并且有类名。
 */
public class LocalInnerClass {
    public static void main(String[] args) {
        new localouter1().outsum();
        //输出为:
//        在外部类访问内部类成员
//        内部类num1: 200
//        外部类num1: 100
    }
}

class localouter1{
    private int num1=100;
    public void outsum(){
        //2、不能添加访问修饰符,因为它的地位就是一个局部变量(本质还是一个类)。
        //   局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final
        //   不会被另一个内部类继承
        final class inner1{
            private int num1=200;
            public void insum(){
                //1、可以直接访问外部类的所有成员,包含私有的
                //4、局部内部类---访问---->外部类的成员【访问方式:直接访问】
                //6、如果外部类和局部内部类的成员重名时,默认遵循就近原则,
                //  如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
                //7、localouter1.this 本质就是外部类的对象
                System.out.println("内部类num1: "+num1+"\n外部类num1: "+localouter1.this.num1);
            }
        }

        //5、外部类---访问---->局部内部类的成员【访问方式:创建对象,再访问(注意:必须在作用域内)】
        inner1 inner1 = new inner1();
        System.out.println("在外部类访问内部类成员");
        inner1.insum();
    }
    public void outf(){
        //下边报错,
        //3、作用域:仅仅在定义它的方法或代码块中。
        //insum();
    }


}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值