重返Java面向对象(超详细)(初级+高级)以及单例设计模式和抽象模板模式

面向对象初级

封装encapsulation

封装就是把抽象出的数据[属性]和对数据的操作[方法]封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作[方法],才能对数据进行操作

现实生活中的封装:如电视机。当用户按下电视机的音量增减按钮时,音量增减的内部电路的实现细节用户是不需要知道的。这时,按钮相当于被授权的操作,内部电路的实现细节就相当于抽象出的数据和对数据的操作。

封装的理解和好处

在这里插入图片描述

封装的实现步骤

在这里插入图片描述

封装快速入门

代码实现

class Person{
    public String name;//名字公开
    private int age;
    private double salary;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        if (name.length() > 1 && name.length() < 7) {
            this.name = name;
        }
        else {
            System.out.println("名字长度不合理");
        }
    }

    public int getAge() {

        return age;
    }

    public void setAge(int age) {
        if (age > 1 && age < 121) {
            this.age = age;
        }
        else{
            System.out.println("年龄设置不合理,给默认年龄");
            this.age = 18;
        }
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {

        this.salary = salary;
    }
}

构造器与setXxx结合,在使用构造器创建对象进行初始化的同时仍可以进行验证

public Person(String name, int age, double salary) {
        setAge(age);//等价于this.setAge(age)
        setName(name);
        setSalary(salary);
    }

继承extend

继承的示意图

在这里插入图片描述

继承基本介绍和基本语法

在这里插入图片描述

继承细节

1.子类继承了父类所有的属性和方法,但是私有属性和方法不能在子类直接访问,要通过公共的方法去访问

比如

class base {
	
}

2.子类必须调用父类的构造器,完成父类的初始化。

public class Base{
    public Base() {
        System.out.println("Base()...");
    }
}

public class Sub extends Base {
    public Sub() {
        //super();//表示调用父类无参构造器
        System.out.println("Sub()...");
    }
}

Sub sub = new Sub();
//会输出Base()...
//     Sub()...

在这里插入图片描述

public class Base{
//    public Base() {
//        System.out.println("Base()...");
//    }
    public Base(String name) {
        System.out.println("Base(String name)...");
    }
}

public class Sub extends Base {
    public Sub() {
        super(String name);
        System.out.println("Sub()...");
    }
}

Sub sub = new Sub();
//会输出Base(String name)...
//     Sub()...

4.如果希望指定去调用父类的某个构造器,则得显式地调用一下:super(参数列表)

5.super在使用时,需要放在构造器第一行

6.super()和this()都只能放在构造器第一行,因此这两个方法不能共存在一个构造器

在这里插入图片描述

在这里插入图片描述

继承的本质分析

继承的内存布局

在这里插入图片描述

继承的查找逻辑

在这里插入图片描述

super

基本介绍及基本语法

在这里插入图片描述

使用细节

在这里插入图片描述
在这里插入图片描述

super和this的比较

在这里插入图片描述

方法重写
在这里插入图片描述

多态polymorphism

多态的基本介绍和多态的具体体现

在这里插入图片描述

对象的多态

在这里插入图片描述

向上转型

在这里插入图片描述

Java向上转型的作用(有详细代码介绍)

向下转型

向下转型的目的是调用子类的特殊方法和属性。

在这里插入图片描述

animal是向上转型出来的。Animal animal = new Cat();

animal是指向Cat类型的引用

在对animal进行向下转型时,只能强转为Cat类型。

多态的注意事项和细节讨论

属性没有重写之说,属性的值看编译类型

instanceOf 比较操作符,用于判断对象的类型是否为XX类型或XX类型的子类型

动态绑定机制DynamicBinding(重要)

在这里插入图片描述

java的动态绑定机制
  1. 当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定
  2. 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
案例分析
为什么base.Sum()为30?

当调用对象方法的时候,该方法会和该对象的内存地址/运行类型绑定

base的运行类型是子类Sub,getI()是一个方法,与base的运行类型Sub绑定,所以调用了子类Sub的getI(),为20,那么return的就是20+10=30了

为什么base.Sum1()为20?

当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用

return的还是编译类型Base中的属性i=10,那么return的就是20

public class dynamicBinding {
    public static void main(String[] args) {
        Base base = new Sub();
        System.out.println(base.Sum());//30
        System.out.println(base.Sum1());//20
    }
}

class Base {
    private int i = 10;

    public int Sum() {
        return getI() + 10;
    }
    public int Sum1() {
        return i + 10;
    }

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }
}

class Sub extends Base {
    private int i = 20;

    @Override
    public int getI() {
        return i;
    }

    @Override
    public void setI(int i) {
        this.i = i;
    }
}

多态数组

父类Person与两个子类Student和Teacher

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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 String say() {
        return "name = " + name + ", age = " + age;
    }
}

public class Student extends Person{
    private double score;

    public Student(String name, int age, double score) {
        super(name, age);
        this.score = score;
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }

    @Override
    public String say() {
        return super.say() + ", score = " + score;
    }

    public void Study() {
        System.out.println(getName() + " is studying");
    }
}

public class Teacher extends Person{
    private int salary;

    @Override
    public String say() {
        return super.say() + ", salary = " + salary;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    public Teacher(String name, int age, int salary) {
        super(name, age);
        this.salary = salary;
    }

    public void Teach() {
        System.out.println(getName() + " is teaching
    }
}
public class main {
    public static void main(String[] args) {
        Person[] persons = new Person[5];//多态数组
        persons[0] = new Person("Mike",20);
        persons[1] = new Student("Tom",18,95);
        persons[2] = new Student("Jack",19,61);
        persons[3] = new Teacher("Lucy",30,15000);
        persons[4] = new Teacher("Elizabeth",40,20000);

        for (Person person : persons) {//增强for
//            System.out.println(person.say());
            if (person instanceof Teacher){//如果person是Teacher的实例或Teacher子类的实例
                ((Teacher) person).Teach();//向下转型,调用Teach()方法
            }
            if (person instanceof Student){
                ((Student) person).Study();
            }
        }
    }
}

多态参数

在这里插入图片描述

上代码

public class Employee {
    private String name;
    private int salaryPerMonth;

    public Employee() {
    }

    public int getAnnual() {
        return 12 * salaryPerMonth;
    }

    public Employee(String name, int salaryPerMonth) {
        this.name = name;
        this.salaryPerMonth = salaryPerMonth;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalaryPerMonth() {
        return salaryPerMonth;
    }

    public void setSalaryPerMonth(int salaryPerMonth) {
        this.salaryPerMonth = salaryPerMonth;
    }
}

public class Manager extends Employee{
    private int bonus;

    public Manager(String name,int salaryPerMonth,int bonus) {
        super(name, salaryPerMonth);
        this.bonus = bonus;
    }

    public int getBonus() {
        return bonus;
    }

    public void setBonus(int bonus) {
        this.bonus = bonus;
    }

    public void manage() {
        System.out.println(this.getName() + " is managing.");
    }

    @Override
    public int getAnnual() {
        return super.getAnnual() + getBonus();
    }
}

public class Worker extends Employee{
    public void work() {
        System.out.println(this.getName() + " is working");
    }

    public Worker(String name, int salaryPerMonth) {
        super(name, salaryPerMonth);
    }

    @Override
    public int getAnnual() {
        return super.getAnnual();
    }
}

Test类

public class Test {
    public static void main(String[] args) {
        Employee manager = new Manager("Jack",50000,200000);
        Employee worker = new Worker("Mike",3000);

        Test test = new Test();
        test.showEmpAnnual(manager);//800000
        test.showEmpAnnual(worker);//36000

        test.testWork(manager);//Jack is managing.
        test.testWork(worker);//Mike is working.
    }

    public void showEmpAnnual(Employee employee) {
        System.out.println(employee.getAnnual());//动态绑定机制
    }

    public void testWork(Employee employee) {
        if(employee instanceof Worker) {
            ((Worker) employee).work();//向下转型
        }
        else if(employee instanceof Manager) {
            ((Manager) employee).manage();
        }
        else {
            System.out.println("不做任何处理...");
        }
    }
}

Object类

equals

==和equals的对比

==
在这里插入图片描述

equals方法

equals:是Object类中的方法,默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如Integer,String

	//object类的equals
	public boolean equals(Object obj) {
        return (this == obj);//判断引用的地址是否相等
    }
	//Integer类的equals
	public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();//判断内容是否相等
        }
        return false;
    }

		Integer integer1 = new Integer(1000);
        Integer integer2 = new Integer(1000);
        System.out.println(integer1 == integer2);//false
        System.out.println(integer1.equals(integer2));//true

重写equals方法

public class Equals02 {
    public static void main(String[] args) {
        Person person1 = new Person("Jack",18,'男');
        Person person2 = new Person("Jack",18,'男');
        System.out.println(person1.equals(person2));//没重写equals之前,调用Object中的equals,返回false;重写equals之后,返回true
    }
}

class Person{
    private String name;
    private int age;
    private char gender;

    public Person(String name, int age, char gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    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 char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o instanceof Person){
            Person p = (Person) o;
            return p.age == this.age && p.gender == this.gender && p.name == this.name;
        }
        return false;
    }
}

hashCode

hashCode()会在集合的底层源码中用到,是一个整数,主要根据地址号得到。

在这里插入图片描述

public class HashCode_ {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new A();
        A a3 = a1;
        System.out.println("a1.hashCode() = " + a1.hashCode());
        System.out.println("a2.hashCode() = " + a2.hashCode());
        System.out.println("a3.hashCode() = " + a3.hashCode());

    }
}
class A{

}

//a1.hashCode() = 1784662007
//a2.hashCode() = 1789550256
//a3.hashCode() = 1784662007

第(2)点一定成立

第(3)点可能不成立,两个不同对象可能会发生碰撞,概率极小。

toString

在这里插入图片描述

object中的toString

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
//getClass.getName() 类的全类名(包名+类名)
//Integer.toHexString(hashCode()) 将对象的hashCode值转成16进制字符串

示例

没有重写toString

public class toString_ {
    public static void main(String[] args) {
        Worker jack = new Worker("Jack", 1000, 31);
        System.out.println(jack.toString());
    }
}
class Worker{
    private String name;
    private int salary;
    private int age;

    public Worker(String name, int salary, int age) {
        this.name = name;
        this.salary = salary;
        this.age = age;
    }
}
//polymorphism.Object_.Worker@6a5fc7f7

重写toString之后

public class toString_ {
    public static void main(String[] args) {
        Worker jack = new Worker("Jack", 1000, 31);
        System.out.println(jack.toString());
    }
}
class Worker{
    private String name;
    private int salary;
    private int age;

    public Worker(String name, int salary, int age) {
        this.name = name;
        this.salary = salary;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Worker{" +
                "name='" + name + '\'' +
                ", salary=" + salary +
                ", age=" + age +
                '}';
    }
}
//Worker{name='Jack', salary=1000, age=31}
finalize

在这里插入图片描述

System.gc()可以主动触发垃圾回收机制,调用finalize方法

断点调试debug

在这里插入图片描述

debug如何进入源码

Settings ==> Build,Execution,Deployment ==> Debugger ==> Stepping

取消勾选java.*javax.*

在这里插入图片描述

F7 step into:单步执行,遇到子函数就进入并且继续单步执行(简而言之,进入子函数);

F8 step over:在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子函数整个执行完再停止,也就是把子函数整个作为一步。有一点,经过我们简单的调试,在不存在子函数的情况下是和step into效果一样的(简而言之,越过子函数,但子函数会执行)。

Shift + F8 step out:当单步执行到子函数内时,用step out就可以执行完子函数余下部分,并返回到上一层函数。

F9 resume program 在分析复杂问题时,非常有用
在这里插入图片描述

面向对象高级

static

类变量(静态变量)

在这里插入图片描述

快速入门

在某个类中定义一个类变量,关键字 static。

例如public static int count = 0;(推荐)

或者static public int count = 0;

该变量最大的特点就是会被该类的所有对象实例共享

public class example {
    public static void main(String[] args) {
        Child child1 = new Child("张三");
        child1.Join();
        child1.count++;
        Child child2 = new Child("李四");
        child2.Join();
        child2.count++;
        Child child3 = new Child("王五");
        child3.Join();
        child3.count++;
        System.out.println("共有 " + Child.count + " 个小孩加入了游戏...");
        System.out.println(child1.count);//3
        System.out.println(child2.count);//3
        System.out.println(child3.count);//3
    }
}

class Child {
    private String name;
    public static int count = 0;

    public Child(String name) {
        this.name = name;
    }
    public void Join() {
        System.out.println(name + " 加入了游戏...");
    }
}

类变量是随着类的加载而创建的,所以即使没有创建对象实例也可以访问

public class example {
    public static void main(String[] args) {
        System.out.println(Child.count);//0
    }
}

class Child {
    public static int count = 0;
}
类变量使用注意事项和细节讨论

在这里插入图片描述
在这里插入图片描述

类方法

在这里插入图片描述

快速入门

统计学生交的总学费

public class method_ {
    public static void main(String[] args) {
        Student jack = new Student("Jack");
        Student mike = new Student("Mike");
        jack.payFee(100);
        mike.payFee(200);

        //输出当前收到的总学费
        Student.showFee();//300
    }
}

class Student {
    private String name;
    private static double fee = 0;

    public Student(String name) {
        this.name = name;
    }

    public static void payFee(double fee) {
        Student.fee += fee;
    }

    public static void showFee() {
        System.out.println("总学费有:" + Student.fee);
    }
}
什么时候使用静态方法?

如果我们希望不创建实例,也可以调用某个方法时(当成工具类),把方法做成静态方法非常合适。如Arrays类、Math类、Collections集合类

在实际开发中,往往会将一些通用的方法,设计成静态方法,这样我们不需要创建对象就可以使用这些方法,比如冒泡排序,打印数组等。

类方法使用注意事项和细节讨论

在这里插入图片描述
在这里插入图片描述

小练习

在这里插入图片描述

main方法

main方法语法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

特别提示

在这里插入图片描述

public class Main01 {
    private static String name = "Lucy";

    private int n1 = 100;

    public static void hello() {//只能调用静态成员和静态方法
        System.out.println("Main01中的静态hello方法被调用 : " + "hello " + name);
    }

    public void hi() {//既可以调用静态成员和静态方法,也可以调用非静态成员和非静态方法
        System.out.println("Main01中的非静态hi方法被调用 : " + "hi " + name);
    }

    public static void main(String[] args) {
        //main方法可以直接调用本类内的静态成员
        System.out.println("name = " + name);
        hello();

        //main方法中,在调用本类的非静态成员时,要先对类实例化
        Main01 main01 = new Main01();
        main01.hi();
        System.out.println(main01.n1);
    }
}

代码块

在这里插入图片描述

代码块的好处和案例演示

在这里插入图片描述

案例演示

public class example {
    public static void main(String[] args) {
        new Movie("Avatar: The Way of Water",51.8,"James Cameron");
    }
}

class Movie {
    private String name;
    private double price;
    private String director;

    {
        System.out.println("观众入场...");
        System.out.println("电影屏幕打开...");
        System.out.println("电影正式开始...");
    }

    public Movie(String name) {
        /*System.out.println("观众入场...");
        System.out.println("电影屏幕打开...");
        System.out.println("电影正式开始...");*/
        System.out.println("Movie(String name)被调用");
        this.name = name;
    }

    public Movie(String name, double price) {
        /*System.out.println("观众入场...");
        System.out.println("电影屏幕打开...");
        System.out.println("电影正式开始...");*/
        System.out.println("Movie(String name, double price)被调用");
        this.name = name;
        this.price = price;
    }

    public Movie(String name, double price, String director) {
        /*System.out.println("观众入场...");
        System.out.println("电影屏幕打开...");
        System.out.println("电影正式开始...");*/
        System.out.println("Movie(String name, double price, String director)被调用");
        this.name = name;
        this.price = price;
        this.director = director;
    }
}
//输出结果:
//观众入场...
//电影屏幕打开...
//电影正式开始...
//Movie(String name, double price, String director)被调用

在这里插入图片描述

(5) 先调用代码块中的语句,再调用构造器中的语句

使用细节

在这里插入图片描述

static代码块在类加载时被调用,且只能被调用一次

普通代码块在new对象实例时会被调用,new一次,就会调用一次。如果只是使用类的静态成员,普通代码块并不会被执行。

代码块的调用顺序

在这里插入图片描述
在这里插入图片描述

public class detail02 {
    public static void main(String[] args) {
        new BBB();
    }
}

class AAA {
    {
        System.out.println("AAA的普通代码块...");
    }
    public AAA() {
        System.out.println("AAA() 构造器被调用...");
    }
}

class BBB extends AAA{
    {
        System.out.println("BBB的普通代码块...");
    }

    public BBB() {
        System.out.println("BBB() 构造器被调用...");
    }
}

在这里插入图片描述

单例设计模式

什么是设计模式
在这里插入图片描述

什么是单例模式

wiki上的解释

In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to a singular instance. One of the well-known “Gang of Four” design patterns, which describe how to solve recurring problems in object-oriented software,[1] the pattern is useful when exactly one object is needed to coordinate actions across a system.

More specifically, the singleton pattern allows objects to:[2]

  • Ensure they only have one instance
  • Provide easy access to that instance
  • Control their instantiation (for example, hiding the constructors of a class)

The term comes from the mathematical concept of a singleton.

在这里插入图片描述

饿汉式(即使没有需要使用实例对象,也会在类加载的时候创建实例对象)

在这里插入图片描述

public class singleTon01 {
    public static void main(String[] args) {
        GirlFriend instance = GirlFriend.getInstance();
        System.out.println(instance);
    }
}

class GirlFriend {
    private String name;

    //为什么是static?静态成员在类加载的时候加载,并且只会加载一次,符合单例设计模式中只生成一个对象实例的要求
    private static GirlFriend gf = new GirlFriend("小红");

    //步骤[单例模式-饿汉式]
    //1.将构造器私有化
    //2.在类的内部直接创建(static)
    //3.提供一个公共的static方法,返回 gf 对象


    private GirlFriend(String name) {
        this.name = name;
    }

    public static GirlFriend getInstance() {
        return gf;
    }

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

懒汉式(在需要使用时才创建实例对象)

public class singleTon02 {
    public static void main(String[] args) {
        Cat cat1 = Cat.getInstance();
        Cat cat2 = Cat.getInstance();
        System.out.println(cat1);
        System.out.println(cat2);
        System.out.println(cat1 == cat2);
    }
}

class Cat {
    private String name;

    private static Cat cat = null;

    private Cat(String name) {
        System.out.println("Cat()构造器被调用...");
        this.name = name;
    }

    public static Cat getInstance() {
        if (cat == null){
            cat = new Cat("小可爱");
        }
        return cat;
    }

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

//Cat()构造器被调用...
//Cat{name='小可爱'}
//Cat{name='小可爱'}
//true

饿汉式与懒汉式对比

在这里插入图片描述

final关键字

基本介绍

在这里插入图片描述

final细节

细节一

final修饰类的某个属性时,必须赋值

1.定义时:如 public final double TAX_RATE=0.08;

2.在构造器中

3.在代码块中

如果final修饰的属性是静态的,则初始化的位置只能是1.定义时和2.在静态代码块中
在这里插入图片描述

细节二

在这里插入图片描述

关于第7点

在这里插入图片描述
在这里插入图片描述

抽象类

在这里插入图片描述

当使用abstract关键字修饰类的方法时,这个类也必须被abstract关键字修饰

在这里插入图片描述

抽象类细节

在这里插入图片描述

在这里插入图片描述

(8)抽象方法不能使用private、final和static来修饰,因为这些关键字都是和重写相违背的

被private修饰的方法,子类无法访问

被final修饰的方法,子类无法重写/覆盖

被static修饰的:重写的作用是为了父类和子类的相同签名的方法,具有不同的行为,从而实现了多态。但是静态方法是被类直接调用的,和对象无关,不存在父子类对象之间的相同方法不同行为,所以也没有多态。

抽象模板模式(Template method pattern)

wiki:

在面向对象编程中,模板方法是Gamma等人[1]确定的行为设计模式之一。 在设计模式一书中。 模板方法是超类(通常是抽象超类)中的一种方法,它根据许多高级步骤定义操作的骨架。 这些步骤本身由与模板方法相同的类中的其他辅助方法实现。

辅助方法可以是抽象方法,在这种情况下子类需要提供具体实现,也可以是钩子方法,在超类中具有空主体。 子类可以(但不是必须)通过覆盖挂钩方法来自定义操作。 模板方法的目的是定义操作的整体结构,同时允许子类改进或重新定义某些步骤。 [2] 动态绑定机制

示例

abstract public class Template {
    abstract public void job();
    public void calculateTime() {
        long start = System.currentTimeMillis();
        job();
        long end = System.currentTimeMillis();
        System.out.println("执行的时间为 " + (end - start));
    }
}
public class AA extends Template{
    @Override
    public void job() {
        int num = 0;
        for (int i = 0;i < 8000000;i++) {
            num += i;
        }
        System.out.print("AA ");
    }

    @Override
    public void calculateTime() {
        super.calculateTime();
    }
}
public class BB extends Template{
    @Override
    public void job() {
        int num = 0;
        for (int i = 0;i < 800000;i++) {
            num *= i;
        }
        System.out.print("BB ");
    }

    @Override
    public void calculateTime() {
        super.calculateTime();
    }
}

public class TestTemplate {
    public static void main(String[] args) {
        AA aa = new AA();
        BB bb = new BB();
        aa.calculateTime();
        bb.calculateTime();
    }
}
//AA 执行的时间为 4
//BB 执行的时间为 2

接口(Interface)

快速入门

注意“统一的规定”

在这里插入图片描述
在这里插入图片描述

public interface UsbInterface {
    public void start();
    public void end();
}
public class Phone implements UsbInterface{
    @Override
    public void start() {
        System.out.println("Phone start to work...");
    }

    @Override
    public void end() {
        System.out.println("Phone end working...");
    }
}
public class Cemera implements UsbInterface{
    @Override
    public void start() {
        System.out.println("Cemera start to work...");
    }

    @Override
    public void end() {
        System.out.println("Cemera end working... ");
    }
}

public class Computer {
    public void ComputerWork(UsbInterface usbInterface){
        usbInterface.start();
        usbInterface.end();
    }
}

public class UsbInterfaceApp {
    public static void main(String[] args) {
        Computer computer = new Computer();
        Phone phone = new Phone();
        Cemera cemera = new Cemera();
        computer.ComputerWork(phone);
        System.out.println("===========");
        computer.ComputerWork(cemera);
    }
}
//Phone start to work...
//Phone end working...
//===========
//Cemera start to work...
//Cemera end working... 

基本介绍

在这里插入图片描述

Java编程语言中的接口是一种抽象类型,用于描述类必须实现的行为。它们类似于协议。接口使用interface关键字声明,并且只能包含方法签名和常量声明(变量声明被声明为静态和final)。在Java 8以下的所有版本中,接口的所有方法都不包含实现(方法体)。从Java 8开始,默认方法和静态方法可以在接口定义中实现然后,在Java 9中添加了私有和私有静态方法。目前,一个Java接口最多可以有六种不同的类型。

接口不能被实例化,而是被实现。实现接口的类必须实现接口中描述的所有非默认方法,或者是一个抽象类。Java中的对象引用可以指定为接口类型;在每种情况下,它们要么必须为空,要么必须绑定到实现接口的对象。

使用接口的一个好处是它们可以模拟多重继承。Java中的所有类都必须有一个基类,唯一的例外是Java .lang. object (Java类型系统的根类);不允许类的多重继承。然而,一个接口可以继承多个接口,一个类可以实现多个接口。

使用场景

顶层设计,利用接口的继承和多态特性来规范类的实现。

案例

需求:

在这里插入图片描述

没有使用接口

方法不规范,不统一。
在这里插入图片描述

使用接口后

类的方法变得规范,统一,符合工业场景了。
在这里插入图片描述

细节

在这里插入图片描述

在这里插入图片描述

内部类

基本介绍以及基本语法

在这里插入图片描述

内部类很重要,底层源码中有大量内部类

内部类的分类

在这里插入图片描述

局部内部类(Local Class)
public class localInnerClass {
    private int n1 = 10;
    private static String name = "张三";
    public void say() {
        int n3 = 30;
        // 局部内部类的作用域只能在定义它的代码块或方法中,
        // 因此也不能用public修饰,但是可以使用final修饰
        class LocalInner01 {//相当于一个局部变量
            int n2 = 40;
            int n1 = 60000;//当内部类成员和外部类成员重名时,遵从就近原则。如果要访问外部类的成员,需要使用 外部类名.this.成员

            public void show() {
                //局部内部类可以直接访问外部类的所有成员,包括私有的
                System.out.println("n1 = " + n1);

                System.out.println("外部类的n1 = " + localInnerClass.this.n1);
            }

        }
        LocalInner01 localInner01 = new LocalInner01();
        localInner01.show();
    }

    public static void main(String[] args) {
        localInnerClass localInnerClass = new localInnerClass();
        localInnerClass.say();

    }
}
//n1 = 60000
//外部类的n1 = 10

在这里插入图片描述

在这里插入图片描述

匿名内部类(Anonymous)

在这里插入图片描述

虽然我们在代码中看不到名字,但系统给它分配了名字

案例演示

public class AnonymousInner01 {
    public static void main(String[] args) {
        Outer01 outer01 = new Outer01();
        outer01.method();
    }
}

class Outer01{
    private int n1 = 10;
    public void method() {
/*        CryInterface tiger = new Tiger();
        tiger.cry();*/
        CryInterface tiger = new CryInterface() {
            @Override
            public void cry() {
                System.out.println("A tiger is crying...");
            }
        };
        tiger.cry();
        //1.如果接口的实现类(或者父类的子类)只需要使用唯一一次,那么这种情况下我们就可以省略掉对该类的定义,而改为使用匿名内部类。
        //2.匿名内部类可以用来简化开发。
        
        //3.tiger的编译类型是? CryInterface
        //4.tiger的运行类型是? Outer01$1
        
        //5.底层
        /*class Outer01$1 implements CryInterface {
            @Override
            public void cry() {
                System.out.println("A tiger is crying...");
            }
        }*/
        //在创建Outer01$1之后,马上创建了Outer01$1的实例,并且把地址返回给了tiger
        
        //6.匿名内部类在使用一次之后就不能再次使用
        
        System.out.println("tiger的匿名内部类的名称是 " + tiger.getClass());
    }

}

interface CryInterface {
    void cry();
}

/*
class Tiger implements CryInterface{
    @Override
    public void cry() {
        System.out.println("A tiger is crying...");
    }
}*/

//A tiger is crying...
//tiger的匿名内部类的名称是 class InnerClass.Outer01$1

匿名内部类的使用场景

当作实参直接传递,简洁高效

public class AnonymousInner01 {
    public static void main(String[] args) {
        show(new CryInterface() {
            @Override
            public void cry() {
                System.out.println("A dog is crying...");
            }
        });
        //传统方法
        show(new Dog());
    }

    public static void show(CryInterface cryInterface) {
        cryInterface.cry();
    }
}

interface CryInterface {
    void cry();
}
//类->实现接口CryInterface  在编程中属于硬编码
//当我们修改类中的方法时,所有的Dog实例都会被修改
class Dog implements CryInterface {
    @Override
    public void cry() {
        System.out.println("A dog is crying...");
    }
}
//A dog is crying...
//A dog is crying...

练习

public class AnonymousInner02 {
    public static void main(String[] args) {
        Clock clock = new Clock();
        clock.AlarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("上课啦,叮叮叮...");
            }
        });
        clock.AlarmClock(new Bell() {
            @Override
            public void ring() {
                System.out.println("下课啦,呱呱呱...");
            }
        });
    }
}

interface Bell {
    void ring();
}

class Clock {
    public void AlarmClock(Bell bell) {
        bell.ring();
    }
}
成员内部类(Member Class)

在这里插入图片描述

public class MemberClass {
    public static void main(String[] args) {
        Outer02 outer02 = new Outer02();
        outer02.method();
    }
}

class Outer02 {
    private int n1 = 10;
    public String name = "张三";

    class Inner02 {//成员内部类,地位相当于外部类的一个成员,所以也可以用private protected public 来修饰
        public void say() {
            //成员内部类的方法可以直接访问外部类的成员
            System.out.println("n1 = " + n1 + " name = " + name);
        }
    }

    public void method() {
        Inner02 inner02 = new Inner02();
        inner02.say();
    }
}
//n1 = 10 name = 张三

在这里插入图片描述

public class MemberClass {
    public static void main(String[] args) {
        //使用成员内部类的方式
        //1.
        Outer02.Inner02 inner02 = outer02.new Inner02();
        inner02.say();
        //2.
        Outer02.Inner02 instance = outer02.getInstance();
        instance.say();
    }
}

class Outer02 {
    private int n1 = 10;
    public String name = "张三";

    class Inner02 {//成员内部类,地位相当于外部类的一个成员,所以也可以用private protected public 来修饰
        public void say() {
            //成员内部类的方法可以直接访问外部类的成员
            System.out.println("n1 = " + n1 + " name = " + name);
        }
    }

    public Inner02 getInstance() {
        return new Inner02();
    }

}

静态内部类static class

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Fantasy`

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值