Java面向对象高级应用

目录

前言

一、static

1.1 static修饰成员变量

1.2 static的应用场景

1.3 static的修饰方法

1.4 static修饰方法的应用场景

1.5 static的注意事项

1.6 static代码块

1.7 static应用知识(单例设计模式)

1.7.1 饿汉式单例模式

1.7.2 懒汉式单例模式

二、继承

2.1 继承的概述

2.2 继承有哪些好处

2.3 继承相关的注意事项

2.3.1 权限修饰符

2.3.2 单继承与object类

2.3.1.1 单继承

2.3.1.2 Object类

2.3.3 方法重写

2.3.4 子类中访问其他成员的特点

2.3.5 子类构造器的特点

2.3.6 子类构造器的应用场景

三、多态

3.1 多态的概述

3.2 使用多态的优点

四、final关键字

4.1 补充知识:常量

五、抽象类

5.1 模板设计方法的写法

六、接口

6.1 接口的概述

6.2 使用接口的好处

6.3 接口的综合案例

6.4 JDK8开始、新增的方法

6.5 接口的多继承和注意事项

七、内部类

7.1 内部类的概述

7.2 成员内部类

7.3 静态内部类

7.4 匿名内部类

7.4.1 匿名内部类常见的使用场景

八、枚举

8.1 枚举常见的应用场景

九、泛型

9.1 泛型的概述

9.2 泛型接口

9.3 泛型方法

9.4 泛型的注意事项


前言

java面向对象高级笔记复盘【已完】,后续更新在常用API(一)中!


一、static

1.1 static修饰成员变量

  • 类变量:有static修饰,属于类,在计算机中只有一份,会被类的全部对象所共享
  • 实例变量(对象的变量):无static修饰,属于每个对象。

1.static是什么?

static:静态,修饰成员变量、成员方法

2.static修饰成员变量叫什么?怎么使用?有什么特点?

类变量(静态成员变量)

类名.类变量(推荐),对象名.类变量(不推荐)

3.无static修饰的成员变量叫什么?怎么使用?有什么特点?

实例变量(对象变量)

对象.实例变量

属于对象,每个对象中都有一份

1.2 static的应用场景

在开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改)则该数据可以定义成类变量来记住

1.成员变量有几种?各自在什么情况下定义?

  • 类变量:数据只需要一份,且需要被共享式(访问、修改)
  • 实例变量:每个对象都要有一份,数据各不同(如:name、score、age)

2.访问自己类中的类变量,是否可以省略类名不屑?

可以的,在某个类中访问其他类里的类变量,必须带类名访问

1.3 static的修饰方法

1.static修饰的成员方法叫什么?如何使用?

  • 类方法(静态方法)
  • 属于类,可以直接使用类名访问呢,也可以用对象访问

2.无static修饰的成员方法叫什么?如何使用?

  • 实例方法(对象的方法)
  • 属于对象,只能用对象访问

1.4 static修饰方法的应用场景

1.为什么工具类中的方法要用类方法,而不用实例方法?

  • 实例方法需要创建对象来调用,此时对象只是为了调用方法,对象占内存,会浪费内存空间
  • 类方法,直接用类名调用,调用方便,节省内存

注:工具类中没有创建对象的需求,建议将工具类的构造器进行私有

2.类方法有哪些应用场景?

  • 可以用设计工具类

3.工具类是什么?有什么好处?

  • 工具类中的方法都是类方法,每个类方法都是用来完成一个功能
  • 提高了代码的复用性;调用方便,提高开发效率

4.为什么工具类要使用类方法,而不是实例方法?

  • 实例方法需要创建对象来调用,会浪费内存空间

5.工具类定义有什么要求?

  • 工具类不需要创建对象,建议将工具类进行私有化!

1.5 static的注意事项

注意事项:

  • 类方法可以访问类成员,不可以访问实例成员
  • 实例方法可以访问类成员,也可以访问实例成员
  • 实例方法可以出现this关键字,类方法中不可以

1.6 static代码块

1.静态代码块

  • 格式:static{}
  • 特点:类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次
  • 作用:完成类的初始化,例如:对类变量的初始化赋值

2.实例代码块

  • 格式:{}
  • 特点:每次创建对象时,都会执行实例代码块,并在构造器前执行
  • 作用:和构造器一样,都是用来完成对象的初始化。例如:对实例变量及逆行初始化赋值

1.7 static应用知识(单例设计模式)

1.什么时设计模式?

  • 一个问题通常有n中解法,其中肯定有一种解法时最优的,这个最有的解法被人总结出来,称为设计模式
  • 设计模式一般来说有20多种,对20多种软件开发中会遇到问题

单例设计模式:确保一个类只有一个对象

写法:

  • 把类的构造器私有
  • 定义一个类变量记住类的一个对象
  • 定义一个类方法,返回对象

1.7.1 饿汉式单例模式

2.单例怎么限额?饿汉式单例的特点是什么?

  • 把类的构造器私有;定义一个类变量存储类的一个对象;提供一个类方法返回对象
  • 特地:在获取类的对象时,对象已经创建了

3.单例哪些应用场景,有哪些好处?

  • 任务管理器对象、获取运行时对象

1.7.2 懒汉式单例模式

特点:拿对象时,才开始创建对象

二、继承

2.1 继承的概述

1.什么时继承?继承后有什么特点?

  • 继承就是用extend关键字,让一个类和另一个类建立起一种父子关系
  • 子类可以继承父类非私有的成员

2.带继承关系的类,Java会怎么创建它的对象?对象创建出来后,可以直接访问哪些成员?

  • 带继承关系的类,Java会用类和父类,这多张设计图来一起创建类的对象
  • 对象能直接访问什么成员,是由子父类这多种设计图共同决定,这多种设计图对外暴露了什么成员,对象就可以访问什么成员

2.2 继承有哪些好处

特点:减少重复的代码

2.3 继承相关的注意事项

2.3.1 权限修饰符

用来限制类中成员(成员变量、成员方法、构造器、代码块……)能够被访问的范围

2.3.2 单继承与object类

2.3.1.1 单继承

java时单继承方式,一个类只能继承一个直接父类,java中的类不支持多继承,但支持多层继承

2.3.1.2 Object类
  • object类时java所有类的祖宗类,写任何一个类时,其实都是object的子类或者子孙类
  • Java创建时,没有继承任何类时,会默认继承object类(object隐藏)

2.3.3 方法重写

1.什么时方法重写?

  • 当子类觉得父类中的某个方法不好用,或者无法满足自己的需求时,子类可以重写一个方法名称,参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
  • 注:重写后,方法的访问,Java会遵循就近原则

2.方法重写的注意事项

  • 重写小技巧:使用@Override注解,他可以指定java编译器,检查我们方法重写的格式是否正确,代码可读性也会更好。
  • 子类重写父类方法时,访问权限必须大于或者等于父类该方法的权限(public>protected>缺省)
  •  重写的方法返回值类型,必须与被重写方法的返回值类型一样,或者范围更小。
  • 私有方法、静态方法不能被重写,如果重写会报错的。

3.方法重写在开发中常见的应用场景

当子类觉得父类的方法不好用,或者不满足自己的需求时,就可以用方法重写

  • 子类重写Object类的toString()方法,以便返回对象的内容

2.3.4 子类中访问其他成员的特点

1.在子类方法中访问其他成员(成员变量、成员方法),是依照就近原则

  • 先子类局部范围找
  • 然后子类成员范围找
  • 然后父类成员范围找,如果父类范围还没有找到则报错

2.如果子父类中,出现了重名的成员,会优先使用子类的,如果此时一定要在子类中使用父类的怎么办?

  • 可以通过super关键字,指定访问父类的成员:super.父类成员变量/父类成员方法

2.3.5 子类构造器的特点

子类的全部构造器,都会先调用父类的构造器,再执行自己,其中父类如果是无参的构造器有个默认的super(),子类构造函数里面也有个默认的super()调用的方法

1.怎么将父类无参构造器取消?

就需要在父类中添加一个有参的构造器-》子类就会报错(解决方法:在子类中添加super()调用父类的有参构造器就不会报错了)

结论:

  • 子类的全部构造器,都会先调用父类的构造器,再执行自己
  • 默认情况下,子类全部构造器的第一行代码都是 super()(写不写都有),它会调用父类的无参数构造器
  • 如果父类没有无参数构造器,则我们必须在子类构造器的第一行手写super(...),指定去调用父类的有参数构造器。

2.3.6 子类构造器的应用场景

补充知识:

  • this(..)调用兄弟构造器
  • 任意类的构造器中,都可以通过this(...)去调用该类的其他构造器。

总结:

1.子类构造器有啥特点?

子类中的全部构造器,都必须先调用父类的构造器,再执行自己

2.super(...)调用父类有参数构造器的常见应用场景是什么?

为对象中包含父类这部分的成员变量进行赋值

3.this(...)的作用是什么?

在构造器中调用本类的其他构造器

4.this(...)和super(...)的使用需要注意什么?

都必须放在构造器的第一行

三、多态

3.1 多态的概述

1.什么是多态?

多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态

2.多态的前提

有继承/实现关系;存在父类引用子类对象;存在方法重写

3.多态的注意事项

多态是对象、行为的多态,Java中的属性(成员变量)不谈多态

3.2 使用多态的优点

  • 在多态形式下,右边对象是解耦合的,更便于扩展和维护
  • 定义方法时,使用父类类型的形参,可以接收一切子类对象,扩展性更强、更便利

1.使用多态有什么好处?存在什么问题?

  • 可以解耦合,扩展性更强;使用父类类型的变量作为方法的形参时,可以接收一切子类对象
  • 多态下不能直接调用子类的独有方法

2.类型转换有几种形式?能解决什么问题?

  • 自动类型转换、强制类型转换
  • 可以把对象转换成其真正的类型,从而解决了多态下不能调用子类独有方法的问题

3.强制类型转换需要注意什么?

  • 存在继承/实现时,就可以进行强制类型转换,编译阶段不会报错
  • 但是,运行时,如果发现对象的真实类型与强转后的类型不同会报错(ClassCastException)

4.强制类型转换前?Java建议我们做什么事情?

  • 使用instanceof判断当前对象的真实类型:对象instanceof类型

四、final关键字

  • final关键字是最终的意思,可以修饰(类、方法、变量)
  • 修饰类:该类被称为最终类,特点是不能被继承了
  • 修饰方法:该方法被称为最终方法,特点是不能被重写了
  • 修饰变量:该变量只能被赋值一次

注:

  • final修饰基本类型的变量,变量存储的数据不能被改变
  • final修饰引用类型的变量,变量存储的地址不能被改变,但地址所指向对象的内容是可以被改变的

4.1 补充知识:常量

  • 使用了 static final修饰的成员变量就被称为常量
  • 作用:通常用于记录系统的配置信息

使用常量的优点:

  • 代码可读性更好,可维护性也更好
  • 程序编译后,常量会被“宏替换”,出现常量的地方全部会被替换成其记住的字面量,这样可以保证使用常量和直接用字面量的性能是一样的。

五、抽象类

  • 在java中有一个关键字叫:abstract,它就是抽象的意思,可以用它修饰类、成员方法
  • abstract修饰类,这个类就是抽象类;修饰方法,这个方法就是抽象方法

注:

  • 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
  • 类该有的成员(成员变量、方法、构造器)抽象类都可以有
  • 抽象类最主要的特点:抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现
  • 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类

1、抽象类、抽象方法是什么样的?

  • 都是用abstract修饰的;抽象方法只有方法签名,不能写方法体

2抽象类有哪些注意事项和特点?

  • 抽象类中可以不写抽象方法,但有抽象方法的类一定是抽象类
  • 类有的成员(成员变量、方法、构造器)抽象类都具备
  • 抽象类不能创建对象,仅作为一种特殊的父类,让子类继承并实现
  • 一个类继承抽象类,必须重写完抽象类的全部抽象方法,否则这个类也必须定义成抽象类

3.抽象类的应用场景和好处是什么?

两种主要的应用场景

  • (1)用抽象类,我们可以把子类中相同的代码,包括方法签名都抽上来,这样能更好的支持多态,以提高代码的灵活性。
  • (2)反过来用,我们不知道系统未来具体的业务实现时,我们可以先定义抽象类,将来让子类去继承实现,以方便系统的扩展。

5.1 模板设计方法的写法

1.定义一个抽象类

2.里面定义两个方法

  • 一个是模板方法:把相同代码放里面去。
  • 一个是抽象方法:具体实现交给子类完成

建议使用final关键字修饰模板方法,为什么?

  • 模板方法是给对象直接使用的,不能被子类重写。
  • 一旦子类重写了模板方法,模板方法就失效了。

六、接口

6.1 接口的概述

Java提供了一个关键字interface,用这个关键字我们可以定义出一个特殊的结构:接口

  • 注:接口不能创建对象;接口是用来被类实现(implements)的,实现接口的类称为实现类
  • 实现类实现多个接口,必须重写完全部接口的全部抽象方法:一个类可以实现多个接口(接口可以理解成干爹),方法,否则实现类需要定义成抽象类。

6.2 使用接口的好处

  • 弥补了类单继承的不足,一个类同时可以实现多个接口
  • 让程序可以面向接口编程,这样程序员就可以灵活方便的切换各种业务实现

1.使用接口有啥好处,第一个好处是什么?

  • 可以解决类单继承的问题,通过接口,我们可以让一个类有一个亲爹的同时,还可以找多个干爹去扩展自己的功能。

2.为什么我们要通过接口,也就是去找干爹,来扩展自己的功能呢?

  • 因为通过接口去找干爹,别人通过你implements的接口,就可以显性的知道你是谁,从而也就可以放心的把你当作谁来用了。

3.使用接口的第二个好处是什么?

  • 一个类我们说可以实现多个接口,同样,一个接口也可以被多个类实现的。这样做的好处是我们的程序就可以面向接口编程了,这样我们程序员就可以很方便的灵活切换各种业务实现了。

6.3 接口的综合案例

1.创建一个Student类

public class Student {
    private  String name;
    private  char sex;
    private  double score;

    public Student() {
    }

    public Student(String name, char sex, double score) {
        this.name = name;
        this.sex = sex;
        this.score = score;
    }

    public String getName() {
        return name;
    }

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

    public char getSex() {
        return sex;
    }

    public void setSex(char sex) {
        this.sex = sex;
    }

    public double getScore() {
        return score;
    }

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

2.创建一个ClassManager类

import java.util.ArrayList;

public class ClassManager {
    private ArrayList<Student> students=new ArrayList<>();
    private  StudentOperator studentOperator=new StudentOperatorImpt2();

    public ClassManager(){
       students.add(new Student("迪丽热巴",'女',99));
       students.add(new Student("古力娜扎",'女',100));
       students.add(new Student("故而扎哈",'男',80));
       students.add(new Student("卡尔扎巴",'男',60));
    }


    //打印全班的学生信息
    public void printInfo(){
        studentOperator.printAllInfo(students);

    }

    //打印全班全部学生的平均分
    public void printScore(){
        studentOperator.printAverageScore(students);

    }
}

3.创建一个StudentOperator接口

import java.util.ArrayList;

public interface StudentOperator {
    void  printAllInfo(ArrayList<Student> students);
    void  printAverageScore(ArrayList<Student> students);
}

4.创建一个StudentOperatorImpt1类

import java.util.ArrayList;

public class StudentOperatorImpt1 implements StudentOperator{
    @Override
    public void printAllInfo(ArrayList<Student> students) {
        System.out.println("-------------全部学生信息如下:---------------------");
        int count1=0;
        int count2=0;
        for (int i = 0; i <students.size() ; i++) {
            Student s=students.get(i);
            System.out.println("姓名:"+s.getName()+"性别:"+s.getSex()+"成绩:"+s.getScore());
            if(s.getSex()=='男'){
                count1++;
            }else {
                count2++;
            }
        }
        System.out.println("男:"+count1+'\t'+"女:"+count2);
        System.out.println("班级总人数为:"+students.size());
        System.out.println("---------------------------------------");

    }

    @Override
    public void printAverageScore(ArrayList<Student> students) {
        double allScore=0.0;
        double max= students.get(0).getScore();
        double min= students.get(0).getScore();
        for (int i = 0; i < students.size(); i++) {
            Student s=students.get(i);
            if(s.getScore()>max) max=s.getScore();
            if(s.getScore()<min) min=s.getScore();
            allScore+=s.getScore();
        }
        System.out.println("学生的最高分是:"+max);
        System.out.println("学生的最低分是:"+min);
        System.out.println("平均分是:"+(allScore-max-min)/(students.size()-2));
    }
}

5. 在创建一个StudentOperatorImpt2类

import java.util.ArrayList;

public class StudentOperatorImpt2 implements StudentOperator{
    @Override
    public void printAllInfo(ArrayList<Student> students) {
        System.out.println("-------------全部学生信息如下:---------------------");
        int count1=0;
        int count2=0;
        for (int i = 0; i <students.size() ; i++) {
            Student s=students.get(i);
            System.out.println("姓名:"+s.getName()+"性别:"+s.getSex()+"成绩:"+s.getScore());
            if(s.getSex()=='男'){
                count1++;
            }else {
                count2++;
            }
        }
        System.out.println("男:"+count1+'\t'+"女:"+count2);
        System.out.println("班级总人数为:"+students.size());
        System.out.println("---------------------------------------");

    }

    @Override
    public void printAverageScore(ArrayList<Student> students) {
        double allScore=0.0;
        double max= students.get(0).getScore();
        double min= students.get(0).getScore();
        for (int i = 0; i < students.size(); i++) {
            Student s=students.get(i);
            if(s.getScore()>max) max=s.getScore();
            if(s.getScore()<min) min=s.getScore();
            allScore+=s.getScore();
        }
        System.out.println("学生的最高分是:"+max);
        System.out.println("学生的最低分是:"+min);
        System.out.println("平均分是:"+(allScore-max-min)/(students.size()-2));
    }
}

6.创建一个Test类

public class Test {
    public static void main(String[] args) {
        ClassManager classManager=new ClassManager();
        classManager.printInfo();
        classManager.printScore();
    }
}

6.4 JDK8开始、新增的方法

1.JDK8开始,接口中新增了哪些方法?

  • 默认方法:使用default修饰,使用实现类的对象调用。
  • 静态方法:static修饰,必须用当前接口名调用
  • 私有方法:private修饰,jdk9开始才有的,只能在接口内部被调用。
  • 他们都会默认被public修饰。

6.5 接口的多继承和注意事项

  • 接口多继承的作用:便于实现类去实现
  • package interface_attention;
    
    public class Test {
    }
    
    interface A{
        void test1();
    
    }
    interface B{
        void test2();
    }
    interface C{}
    //接口多继承
    interface D extends  A,B,C{}
    
    class E implements D{
    
        @Override
        public void test1() {
            
        }
    
        @Override
        public void test2() {
    
        }
    }
    
    

注意事项(了解):

1.一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承。
2.一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。
3.一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。

4.一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可

package interface_attention;

public class Test {
    public static void main(String[] args) {
        Zi zi=new Zi();
        zi.run();
    }

}


//1.一个接口继承多个接口,如果多个接口中存在方法签名冲突,则此时不支持多继承。
interface I {
    void test1();
}
interface J {
    String test1();
}
/*interface K  extends I,J{

}*/

//2.一个类实现多个接口,如果多个接口中存在方法签名冲突,则此时不支持多实现。
/*class C implements I,J{

}*/

//3.一个类继承了父类,又同时实现了接口,父类中和接口中有同名的默认方法,实现类会优先用父类的。
class Fu{
    public void run(){
        System.out.println("==父类的run方法执行了===");
    }
}
interface IT{
    default void run(){
        System.out.println("接口中的run方法执行了");
    }
}
class Zi extends Fu implements IT{

}

//4.一个类实现了多个接口,多个接口中存在同名的默认方法,可以不冲突,这个类重写该方法即可
interface It1{
    default void test(){
        System.out.println("IT1");
    }
}
interface It2{
    default void test(){
        System.out.println("IT1");
    }

}
class  N implements It1,It2{
    @Override
    public void test() {
        System.out.println("自己的方法");;
    }
}


七、内部类

7.1 内部类的概述

  • 是类中的五大成分之一(成员变量、方法、构造器、内部类、代码块),如果一个类定义在另一个类的内部,这个类就是内部类
  • 场景:当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,就可以把这个事物设计成内部类

内部类包含:成员内部类、静态内部类、局部内部类、匿名内部类

7.2 成员内部类

就是类中的一个普通成员,类似前面我们学过的普通的成员变量、成员方法

Outer.class

package com.itheima.de_inner_class1;

public class Outer {
    private int age = 99;
    public static String a;

    //成员内部类
    public class Inner {
        private String name;
        public static String schoolName;//JDK 16才开始支持定义静态成员的
        private int age = 88;

        public void test() {
            System.out.println(age);
            System.out.println(a);
            int age = 66;


            System.out.println(age);//66
            System.out.println(this.age);//88
            System.out.println(Outer.this.age);//99  使用Outer.this.age来获取外部类的数据

        }

        public String getName() {
            return name;
        }

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

Test.class

package com.itheima.de_inner_class1;

public class Test {
    public static void main(String[] args) {
        Outer.Inner in=new Outer().new Inner();//先new外部类,在new内部类
        in.test();
    }
}

1.成员内部类是什么?如何创建其对象?

  • 就是类中的一个普通成员,类似前面我们学过的普通成员变量、成员方法
  • 外部类名.内部类名 对象名=new 外部类(...).new 内部类(...);

2.成员内部类的实例方法中,访问其他成员有啥特点?

  • 可以直接访问外部类的实例成员、静态成员
  • 可以拿到当前外部类对象,格式是:外部类名.this。

7.3 静态内部类

特点:可以直接访问外部类的静态成员,不可以直接访问外部类的实例成员

Outer.class

package com.itheima.de_inner_class2;

public class Outer {
    private int age;
    public static String schoolName;
    //静态内部类
    public static class Inner {
        private String name;


        public void test() {
            System.out.println(schoolName);

        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }
    public static void test2(){
        System.out.println(schoolName);//可以访问静态内部类的静态成员,不可以访问静态内部类的实例成员(对象成员)
    }

}

Test.class

package com.itheima.de_inner_class2;

public class Test {
    public static void main(String[] args) {
        Outer.Inner in = new Outer.Inner();
        in.test();



    }
}

1.什么是静态内部类?如何创建对象?有啥特点?

  • 有static修饰的内部类
  • 外部类名.内部类名 对象名 =new 外部类.内部类(...);
  • 可以直接访问外部类的静态成员,不能直接访问外部类的实例成员

7.4 匿名内部类

  • 就是一种特殊的局部内部类;所谓匿名:指的是程序员不需要为这个类声明名字。
  • 特点:匿名内部类本质就是一个子类,并会立即创建出一个子类对象
  • 作用:用于更方便的创建一个子类对象

Cat.class

package com.itheima.de_inner_class3;

public class Cat extends Animal {
    @Override
    void cry() {
        System.out.println("jiao");
    }
}

Animal.class

package com.itheima.de_inner_class3;

abstract  class Animal {
    abstract void cry();
}

Test.class

package com.itheima.de_inner_class3;

public class Test {
    public static void main(String[] args) {


      /*  Animal animal = new Cat();
        animal.cry();*/

        //把这个匿名类翻译成一个子类,然后立即创建一个子类的对象出来
        Animal a = new Animal() {
            @Override
            void cry() {
                System.out.println("jiao");
            }
        };
        a.cry();

    }
}

7.4.1 匿名内部类常见的使用场景

通常作为一个参数传输给方法

package de_inner_class4;

public class Test {
    public static void main(String[] args) {
/*       Swimming s1= new Swimming() {
            @Override
            public void swimming() {
                System.out.println("狗游泳飞快");
            }
        };
       go(s1);*/


        go(new Swimming() {
            @Override
            public void swimming() {
                System.out.println("狗游泳飞快");
            }
        });
    }

    //设计一个方法,可以接收swimming接口的一切实现类对象来参加游泳比赛
    public static void go(Swimming s) {
        System.out.println("开始------------------------");
        s.swimming();
    }

}

//猫和狗都要参加游泳比赛
interface Swimming {
    void swimming();
}

1.匿名内部类的书写格式是什么样的 ?

2.匿名内部类有啥特点 ?

  • 匿名内部类本质就是一个子类,并会立即创建出一个子类对象

3.匿名内部类有啥作用、应用场景?

  • 可以更方便的创建出一个子类对象。

八、枚举

枚举是一种特殊的类

  • 枚举类的第一行只能罗列一些名称,这些名称都是常量,并且每个常量记住的都是枚举类的一个对象。
  • 枚举类的构造器都是私有的(写不写都只能是私有的),因此,枚举类对外不能创建对象
  • 枚举都是最终类,不可以被继承。
  • 枚举类中,从第二行开始可以定义类的其他各种成员
  • 编译器为枚举类新增了几个方法,并且枚举类都是继承:java.lang.Enum类的,从enum类也会继承到一些方法。

enum类

package com.itheima.de_enum;

public enum A {
   // 枚举类里面都是一些常量,记住每一个对象
    X,Y,Z;
}

Test类

package com.itheima.de_enum;

public class Test {
    public static void main(String[] args) {
        A a1=A.X;
        A a2=A.Y;
        A a3=A.Z;

    }
}

8.1 枚举常见的应用场景

  • 用来表示一组信息,然后作为参数进行传输。
  • 选择定义一个一个的常量来表示一组信息,并作为参数传输
  • 参数值不受约束
  • 选择定义枚举表示一组信息,并作为参数传输
  • 代码可读性好,参数值得到了约束,对使用者更友好,建议使用!

Enum.class

package com.itheima.de_enum;

public enum Constant {
    BOY,
    GIRL;
}

Test.class

package com.itheima.de_enum;

public class Test2 {
    public static void main(String[] args) {
        provideInfo(Constant.GIRL);
    }

    public static void provideInfo(Constant sex) {
        switch (sex){
            case BOY:
                System.out.println("I M BOY");
                break;
            case GIRL:
                System.out.println("I M GIRL");
                break;
        }
    }

}

九、泛型

9.1 泛型的概述

定义类、接口、方法时,同时声明了一个或者多个类型变量(如:<E>),称为泛型类、泛型接口,泛型方法、它们统称为泛型

也可以技能泛型的继承,但是必须是定义所及继承的类型

9.2 泛型接口

注意:类型变量建议用大写的英文字母,常用的有:E、T、K、V等

Student.class(空项)

Class.class(空项)

Data.interface

package com.itheima.generics_interface;

public interface Data<T>{
    void add(T t);
    void get(T name);
}

TeatcherData.class

package com.itheima.generics_interface;

public class TeacherData implements Data<Teacher>{
    @Override
    public void add(Teacher teacher) {

    }

    @Override
    public void get(Teacher name) {

    }
}

StudentData.class

package com.itheima.generics_interface;

public class StudentData implements Data<Student>{
    @Override
    public void add(Student student) {

    }

    @Override
    public void get(Student name) {

    }
}

同理,上述泛型也可以进行继承其他的类,使用的时候必须是继承他的父类或者被继承的子类

9.3 泛型方法

Test.class

package com.itheima.generics_method;

public class Test {
    public static void main(String[] args) {
       String  rs= test("java");
        System.out.println(rs);
    }

    public static <T> T test(T t) {
        return t;
    }
}

有比如 新建一个Car.class ,BMW 、BENZ类,其中都是空项目

在Test类中实现通配符泛型指定的继承类型

通配符包括上限继承和下限继承

package com.itheima.generics_method;

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        
        ArrayList<Car> cars = new ArrayList<>();
        cars.add(new BMW());
        cars.add(new BENZ());
        go(cars);

        ArrayList<BMW> bmws = new ArrayList<>();
        cars.add(new BMW());
        cars.add(new BMW());
        go(bmws);

        ArrayList<BENZ> benzs = new ArrayList<>();
        cars.add(new BENZ());
        cars.add(new BENZ());
        go(benzs);
        
    }

/*
    //仅仅可以接收Car类下的集合
    public static <T extends Car> void go(ArrayList<T> cars){

    }*/

    //? 通配符,使用泛型的时候可以代表一切类型
    //? 通配符也可以继承car仅能接受car的子类  ?extends Car(上限继承) ? super Car (下限继承)
    public static void go(ArrayList<? extends Car> cars) {
    }
}

9.4 泛型的注意事项

  • 泛型是工作在编译阶段的,一日程序编译成class文件,class文件中就不存在泛型了,这就是泛型擦除
  • 泛型不支持基本数据类型,只能支持对象类型(引用数据类型)

  • 13
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值