【面向对象】下

 一、继承 :extends

把多个类中相同的部分提取到另一个类中,然后让多个类继承自这个类。

继承优点: 提高了代码的复用性 多个类相同的成员可以放到同一个类中 提高了代码的维护性 如果功能的代码需要修改,修改一处即可 让类与类之间产生了关系,是多态的前提 其实这也是继承的一个弊端:类的耦合性很强

开发思想:低耦合,高内聚

java中的继承在使用上有哪些特点:

1、java中的继承不允许一个类同时继承多个类,只能单继承

2、java中的类支持多层继承,形成继承体系

java中的继承使用的注意事项:

1、子类只能继承父类中非私有的成员(成员变量或者成员方法)

2、继承关系中,子类无法继承父类的构造方法,父类构造方法最重要的意义是初始化子类对象之前,必须先对父类做初始化(要想有儿子,必须先有父亲)

3、不要为了部分的功能去使用继承

1、继承与成员变量的关系:

super:子类中要使用父类中的成员,可以使用super.的方式

class Fu{
    int a =10;
}
class Zi extends Fu{
    int a=20;

    public void fun1(){
        System.out.println(a);
        //在子类中想要使用父类中的成员,可以使用super关键字
        System.out.println(super.a);
    }
}
public class Text1 {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.fun1();
    }
}

2、面试题:super关键字与this关键字的区别:

this的使用:

  • 成员变量:this.成员变量名
  • 构造方法:this(..)
  • 成员方法:this.成员方法名(..)

super的使用:

  • 成员变量:super.成员变量名
  • 构造方法:super(..)
  • 成员方法:super.成员方法名(..)

不同点: this在本类中使用 super关键字在子类中使用,代表子类中要使用父类的成员,super不能跨层使用,super只能代表直接父类的引用

三、java中的继承与构造方法的关系

子类中所有的构造方法默认都会访问父类中空参数的构造方法

为什么呢?因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。

每一个构造方法的第一条语句默认都是:super()

回顾上一个案例说的一个结论:定义的时候用构造方法进行初始化,要想初始化子类,必须先初始化父类

注意事项:

1、子类的构造方法中第一句话上面默认会有一个super(),super()的意义就是调用父类的无参构造方法

class Fu1{
    Fu1(){

        System.out.println("这是父类的构造方法");
    }
}

class Zi1 extends Fu1{
    //子类的构造方法中第一句话上面默认会有一个super()
    Zi1(){
        System.out.println("这是子类的构造方法");
    }
}

public class Text2 {
    public static void main(String[] args) {
        Zi1 zi1 = new Zi1();
    }
}
//这是父类的构造方法
//这是子类的构造方法


如果父类中没有无参数的构造方法,有有参数的构造方法,就会报错




2、在此基础之上继续写,如果父类中没有无参构造方法怎么办?

1)解决方案
我们就在子类构造方法第一句话通过super去显示调用父类其他的带参的构造方法,完成父类的初始化

  • 子类调用父类的构造方法,明着写调用带参数的构造方法,完成父类的初始化
  • 先初始化父类,就要使用父类构造方法去初始化,但是父类没有无参的构造方法,
  • 因此给父类的构造方法传值,使得父类初始化

2)解决方案2:子类通过this去调用本类中其他的构造方法,该构造方法要访问量父亲的构造方法。间接地调用父类中的其他构造方法,完成父类的初始化

class Fu1{
    Fu1(String s){

        System.out.println("这是父类的构造方法");
    }
}

class Zi1 extends Fu1{
    //子类的构造方法中第一句话上面默认会有一个super()

    
    //利用子类中的其他构造方法
    Zi1(String s){
        super(s);
    }
    Zi1(){

        //子类调用父类的构造方法,明着写调用带参数的构造方法,完成父类的初始化
        //先初始化父类,就要使用父类构造方法去初始化,但是父类没有无参的构造方法,
        //因此给父类的构造方法传值,使得父类初始化
        //super("你好");
        
        //调用当前对象的构造方法,传参
       this("你好");

        System.out.println("这是子类的构造方法");
    }
}
public class Text2 {
    public static void main(String[] args) {
        Zi1 zi1 = new Zi1();
    }
}

四、继承中成员方法的关系

同名和不同名的方法

  • 通过子类对象去访问一个方法
  • 首先在子类中找
  • 然后在父类中找

如果还是没有就报错。(不考虑父亲的父亲…)

class Fu5{
    public void fun1(){
        System.out.println("这是父类中的fun1方法");
    }
}

class Zi5 extends Fu5{

    public void fun1(){
        System.out.println("这是子类中的fun1方法");
    }

    public void fun2(){
        fun1();//就近原则
    }
}

public class ExtendsDemo5 {
    public static void main(String[] args) {
        Zi5 zi5 = new Zi5();
        zi5.fun2();
    }
}

五、方法的重写

 方法重写的应用:

当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。

特点:如果方法名相同,最终使用的是子类自己的

方法重写:当子类中的方法声明(返回值类型,方法名,参数列表)与父类中的方法声明一样,这样的现象叫做方法的重写, 一般是需要在子类重写的方法上加一个注解@Override,表示该方法是重写方法

方法重写的注意事项

​​​​​1、父类中私有方法不能被重写

2、子类重写父类方法时,访问权限不能更低

3、父类静态方法无法被重写

面试题:方法的重载与方法的重写是什么区别?

1、重载是发生在同一个类中的,而重写是发生在继承关系中。

2、重载是方法名一样,方法参数列表不一样就叫重载,和返回值类型无关

3、重写要求方法返回值类型,方法名,参数列表都要与父类中的一致,只有权限修饰符和方法体的实现不一样

class Fu2{
    public void call(){
        System.out.println("打电话");
    }
}
class Zi2 extends Fu2{
    //重写的方法
    @Override
    public void call(){
        System.out.println("边打电话边玩游戏");
    }

}
public class Text3 {
    public static void main(String[] args) {
        Zi2 zi2 = new Zi2();
        zi2.call();
    }
}
//边打电话边玩游戏

final:是最终的意思

可以修饰类,成员变量,成员方法

1、修饰类,类不能被继承

2、修饰变量,变量就变成了常量,只能被赋值一次

         1)字面值常量

          2)自定义常量:final所修饰的常量

3、修饰方法,方法不能被重写

5、在引用数据类型(比如类)之前加上final关键字,指的是引用数据类型变量的地址值不能被改变

class Fu3{

   final int a=10;
}
class Zi3 extends Fu3{
    public void fun(){
        //被final所修饰的成员变量变成常量,值无法被改变
        //a=20;
        System.out.println(a);
    }

}

public class Final {
    int a=100;
    public static void main(String[] args) {

        // final Zi3 zi3 = new Zi3();
        //zi3.fun();

        //在引用数据类型之前加上final关键字,指的是引用数据类型变量的地址值不能被改变
        final Final f = new Final();
        f.a=100;
        System.out.println(f.a);
    }
}
 

 6、final修饰变量的初始化时机 ,(赋值)在对象构造完毕前即可

不加final,系统会给一个默认值,加上final ,就必须在构造方法之前给对象赋值

class F{

    final int a;
    //2、构造代码块,可以在构造方法之前执行
    {
        a=30;
    }
    F(){
        //1、在构造方法里面赋值
        //a=20;
    }

}

public class Final2 {
    public static void main(String[] args) {
        F f = new F();
        System.out.println(f.a);
    }
}

二、多态:一个事物表现出来的不同状态

猫是一种动物,狗是一种动物,不能反过来说动物是一种猫。

多态的写法:从右往左去读为猫是动物的一种

动物 d = new 猫();

动物 d2 = new 狗();

实现多态的条件:

1、必须要有继承关系

2、要有方法的重写,如果不重写语法上没问题,但是从意思上不合适

3、在创建对象的时候,要有父类的引用指向子类对象

class Animal{
    
    public void fun(){
        System.out.println("动物");
    }
}
   //继承关系
class Cat extends Animal{
    //方法的重写
    @Override
    public void fun(){
        System.out.println("🐱吃🐟");
    }
    
}
public class DuoTai {
    public static void main(String[] args) {
        //父类的引用指向子类的对象
        Animal animal=new Cat();
    }
}

成员访问的特点:

成员变量编译看左边(有没有),运行(结果)看左边
成员方法编译看左边,运行看右边
静态方法编译看左边,运行看左边

静态方法不能算方法的重写

因此子类特有的方法就无法使用。

多态使用的过程中出现的问题:无法使用子类特有的成员 怎么解决?

向下转型:

向下转型有一个前提:转型的类要和父类的引用是一个继承关系

转型之后,就可以使用子类的方法

格式:

Fu fu = new Zi();
Zi zi = (Zi) fu;

class Animal{
    int a=10;
    public void fun(){
        System.out.println("动物");
    }

    public static void fun1(){

        System.out.println("这是父类中的静态方法");
    }
}
   //继承关系
class Cat extends Animal{

    int a=100;
    //方法的重写
    @Override
    public void fun(){
        System.out.println("🐱吃🐟");
    }


    //不是方法的重写,没有加@override
    public static void fun1(){

           System.out.println("这是子类中的静态方法");
    }



    public void fun2(){
        System.out.println("这是子类特有的成员方法");
    }

}
public class DuoTai {
    public static void main(String[] args) {
        //父类的引用指向子类的对象
        Animal animal=new Cat();

        System.out.println(animal.a);//10  成员变量:编译看左,运行看左
        animal.fun1();//静态方法:编译看左,运行看左
        //animal.fun2();//成员方法:编译看左,运行看右。animal中没有fun2()方法,编译不成功
       //向下转型
        Cat cat = (Cat) animal;
        //现在可以使用fun2()方法了
        cat.fun2();

    }
}

曹操和曹植的故事(和三国故事情节无关,纯属个人瞎扯)
曹操和曹植是一对父子关系
class 曹操{
    String name;
    int age;

    public void ability(){
        善于用兵
    }
}

class 曹植 extends 曹操{
    public void ability(){
        善于写诗
    }

    public void playChess(){
        善于下棋
    }
}

有一天,曹操有事卧病不起,突然敌人攻打城池,但是为了不降低士气,于是曹植想了一个办法:开始装自己父亲,替自己的父亲打仗
穿上父亲的衣服,粘上父亲的假胡子
曹操 c = new 曹植();
c.ability(); //在装父亲的期间,只能使用和父亲一样的方法,不能使用自己特有的方法
打完仗了,回到阵营,脱下衣服,撕掉胡子,做回自己
曹植 c2 = (曹植)c; //向下转型
c2.ability();
c2.playChess();

向下转型类型转换异常图: 

多态的好处:

1、提高了程序的维护性(由继承保证)

2、提高了程序的扩展性(由多态保证)

3、多态的弊端: 不能访问子类特有功能, 那么我们如何才能访问子类的特有功能呢? 多态中的转型

抽象类:

抽象类的引入:java提供了一个机制给我们使用,如果将来要定义的类在现实生活中的意思是表达一个抽象的概念,在程序中写的时候应该将这个类定义成抽象类,也就意味着这个类将来没法创建对象(实例化)。

关键字:abstract

特点:

1、一个类加上了abstract关键字就变成了抽象类,抽象类不能被实例化(不能创建对象)。

2、抽象类中可以存在非抽象的方法,也可以存在抽象的方法,但是抽象的方法没有方法体

3、如果一个类中存在抽象方法,这个类必须是抽象类。

4、如果一个具体的类继承自抽象类,必须重写抽象类中的所有抽象方法。

5、抽象类也可以继承抽象类,可以不去重写父抽象类中的抽象方法。

//抽象类
abstract class Animal{

    //2、抽象类中可以存在非抽象的方法,也可以存在抽象的方法,但是抽象的方法没有方法体。
    public void sleep(){
        System.out.println("睡觉");
    }

    //3、如果一个类中存在抽象方法,这个类必须是抽象类。
    //对于吃这个方法而言,也不应该有具体的实现,所以需要将这个方法也变成抽象方法,抽象方法没有方法体,连大括号都没有
    public abstract void eat();
}

//具体的类继承抽象类
class Dog extends  Animal{

   //4、具体的类继承自抽象方法必须要重写该抽象类的方法
   @Override
   public void eat() {
       System.out.println("🐕吃🥩");

   }
}

    //5、抽象类也可以继承抽象类,可以不去重写父抽象类中的抽象方法。
abstract class Demo extends Animal{

}

public class Abstract01 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
    }
}
//🐕吃🥩

抽象类中成员的特点:

​​​​​​ 成员变量:可以是变量也可以是常量

构造方法:可以存在构造方法,写构造方法的意义是为了今后初始化子类之前先初始化本类

成员方法:可以存在抽象方法也可以存在含有具体实现的方法

abstract class Demo2{
    //成员变量可以是常量也可以是变量
    int a;
    final int b=20;
//有构造方法,目的是给子类初始化
    Demo2(){

    }
    //成员方法可以是抽象方法也可以是具体的方法
    public void fun1(){
        System.out.println("吃");

    }
    public abstract void fun2();


}
class DemoZi extends Demo2{
    //具体的类继承自抽象类必须要重写抽象类里的抽象方法
    @Override
    public void fun2() {

    }
}

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

    }
}

抽象类练习

1、2、老师案例 :具体事物:十三期老师,十二期老师 共性:姓名,年龄,讲课

abstract class Teacher{
    String name;
    int age;
    Teacher(){

    }

    public Teacher(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 abstract void teach();

}
class TwentyTwo extends Teacher{
    public TwentyTwo() {
    }

    public TwentyTwo(String name, int age) {
        super(name, age);
    }

    @Override

    public void teach() {
        System.out.println("22期老师讲解Java");

    }
}
class TwentyThree extends Teacher{
    @Override
    public void teach() {
        System.out.println("23期老师讲解python");

    }
}
public class AbstractText {
    public static void main(String[] args) {
        //创建一个22期老师
        TwentyTwo twentyTwo = new TwentyTwo();
        twentyTwo.teach();

        //多态:由于父类是一个抽象类,因此叫抽象多态
        Teacher teacher=new TwentyTwo("小虎",22);
        teacher.teach();//编译看左,运行看右
    }
}

2、假如我们在开发一个系统时需要对员工类进行设计

员工包含3个属性:姓名、工号以及工资。 经理也是员工,除了含有员工的属性外,另为还有一个奖金属性。 请使用继承的思想设计出员工类和经理类。要求类中提供必要的方法进行属性访问。

abstract class Staff{

    String name;
    int id;
    int salary;

    public Staff(String name, int id, int salary) {
        this.name = name;
        this.id = id;
        this.salary = salary;
    }

    public abstract void work();
}
class Manage extends Staff{
    int reward;

    public Manage(String name, int id, int salary, int reward) {
        super(name, id, salary);
        this.reward = reward;
    }

    @Override
    public void work() {
        System.out.println("做ppt");
    }
}

class Personnel extends  Staff{
    public Personnel(String name, int id, int salary) {
        super(name, id, salary);
    }

    @Override
    public void work() {
        System.out.println("写代码");
    }
}


public class AbstractText2 {
    public static void main(String[] args) {
        //使用多态,父类的引用指向子列类的对象
        Staff staff = new Manage("张三", 001, 20000,2000);
        staff.work();
    }
}

1、一个类如果没有抽象方法,可不可以定义为抽象类?

如果可以,有什么意义?

可以。 有意义,表示现实生活中一个抽象概念的汇总,尽管类中没有其他内容,但是从逻辑上是有意义的。

2、abstract不能和哪些关键字共存

private 冲突  私有的,子类不能继承私有成员变量和方法,因为抽象方法本身就是为了今后具体的类继承抽象类去写的。

final 冲突  被finna修饰的方法不能被重写,但是抽象方法就是要被子类继承,所以冲突

static 冲突,静态方法的没法重写

接口:关键字     implements        interface

接口:就是某一个事物本身的功能有限,想要进行扩展功能的时候可以使用接口。当然今后接口的具体使用,是由后面具体的类实现。

例如:有动物类,狗类继承自动物类,有些狗会骑自行车,但不是所有的狗都会骑自行车,所以定义一个接口,接口中有骑自行车的方法。所以java提供了一个机制给我们使用,当我们需要写扩展功能的时候,就可以定义一个接口 ,这里就可以将骑自行车定义成一个接口 ,将来哪些狗需要骑自行车,只需要实现这个接口即可。

1、定义一个接口,接口中有骑自行车方法

2、抽象父类:动物类Animal

3、普通的狗类:Dog

4、经过训练的狗类:SpecialDog

注意事项:

​​​​​​ 1、接口中定义的所有方法只能是 抽象方法 ,并且系统会默认在每一个方法前加上public abstract

2、一个类要想实现接口,使用implements关键字进行实现

3、接口中只能存在常量,默认在变量的前面加上public static final

4、抽象类可以实现接口,但是可以不去实现抽象方法,也可以实现

5、一个具体的类实现接口,必须要实现接口中所有抽象方法

6、一个类可以继承一个类的同时实现多个接口,也可以直接实现多个接口

7、接口没有构造方法,它不能创建对象(不能实例化

定义接口的语句格式 interface 接口名 {         }

注意:接口名的命名方式与类名的命名方式是一样

就将接口看作是一个特殊的类,因为接口编译的时候也会被编译成一个class文件

interface Bike{
    //3、接口中只能存在常量,默认在变量的前面加上public static final
    int a=10;
    //接口里面必须是抽象方法
    void bike();
}
interface Sing{
    void sing();
}
abstract class Animal2{

    String name;
    int age;
    public abstract void eat();
}

class Dog2 extends Animal{
    @Override
    public void eat() {
        System.out.println("🐕吃🥩");
    }
}

//6、一个类可以继承一个类的同时实现多个接口,也可以直接实现多个接口
class SpecialDog extends Animal implements Bike,Sing{
//3、接口中只能存在常量,默认在变量的前面加上public static final
    //a=100
    int b=10;
    @Override
    public void eat() {
        System.out.println("大口吃");
    }

    @Override
    public void bike() {
        System.out.println("骑自行车");
    }


    @Override
    public void sing() {
        System.out.println("唱歌");
    }
}
public class Interface {
    public static void main(String[] args) {

        //因为是接口,会在变量前默认加上public static final 。加了static 属于类成员,所以我们可以通过接口名去调用
        System.out.println(Bike.a);
        
        //类里的成员变量要通过对象去调用
       // System.out.println(SpecialDog.b);

        //接口多态
        Bike b1=new SpecialDog();
        b1.bike();//编译看左,运行看右
    }
}

类和类,类和抽象类,类和接口,接口和接口之间

1、具体的类和具体的类之间只能是继承关系,只能进行单继承,不能多继承,但是可以多重继承,形成继承体系            (继承        单继承  )

2、类和抽象类之间也只能是继承关系,也只能进行单继承,不能多继承,但是呢如果是一个具体的类继承了抽象类,就必须实现抽象类中所有抽象方法

3、类和接口之间是一个实现关系,一个类可以实现多个接口     (实现     单实现    多实现)

4、接口和接口之间是继承关系,并且允许多继承    (继承      单继承      多继承    )

面试题:请问java中允许多继承吗?回答这道题的时候,分别说明类和类之间,接口和接口之间的区别。

猫狗案例

,加入跳高的额外功能

猫: 姓名,年龄 吃

狗: 姓名,年龄 吃

会跳高的猫: 姓名,年龄 吃 跳高

会跳高的狗: 姓名,年龄 吃 跳高 ----------------------

动物类(抽象类): 姓名,年龄 吃(抽象方法)

跳高(接口): 跳高(抽象方法) 猫 extends

动物类: 重写吃方法 狗 extends 动物类: 重写吃方法

会跳高的猫 extends 动物类 implements 跳高: 重写吃方法 重写跳高方法

会跳高的狗 extends 动物类 implements 跳高: 重写吃方法 重写跳高方法

教练和运动员案例(学生分析然后讲解)

乒乓球运动员和篮球运动员。 乒乓球教练和篮球教练。

为了出国交流,跟乒乓球相关的人员都需要学习英语。

请用所学知识: 分析,这个案例中有哪些抽象类,哪些接口,哪些具体类。

参数

形式参数

  • 基本类型: 基本数据类型当作方法的参数的时候,传入的是具体的数值
  • 引用类型:

               具体的类:今后当你看到一个类作为方法形式参数类型的时候,说明要传入该类的对象                   接口:今后当你看到一个接口作为方法形式参数类型的时候,说明要传入的是实现该接                                口的子类对象。

              抽象类:今后当你看到一个抽象类作为方法形式参数类型的时候,说明要传入的是继承                                   该抽象类的具体类的子类对象

              数组:回顾前面的知识

返回值类型

  • 基本类型:基本数据类型当作方法的返回值的,返回的是对应类的数值
  • 引用类型

                  具体的类:今后当你看到一个类作为方法的返回值类型的时候,需要返回的是该类或者                                      是该类的子类对象

                   接口:今后当你看到一个接口作为方法的返回值类型的时候,需要返回的是实现该接                                  口的子类对象

                   抽象类:今后当你看到一个抽象类作为方法的返回值类型的时候,需要返回的是继承                                     该抽象类的具体子

                                 数组

1、类作为方法形式参数类型,说明要传入该类的对象 

class Student{
    public void  study(){
        System.out.println("学习");
    }
}

class StudentDemo{
    //参数类型为一个类,则传入的值为该类的对象
    public void show(Student student){
        student.study();
    }
}
public class ShuJu {
    public static void main(String[] args) {
        StudentDemo studentDemo = new StudentDemo();
        //传入对象
//        Student s = new Student();
//        studentDemo.show(s);
        studentDemo.show(new Student());
    }
}

2、今后当你看到一个接口作为方法形式参数类型的时候,说明要传入的是实现该接                                口的子类对象。

interface Sing1{
    void fun1();
}

//实现该接口的类
class InterImpl implements Sing1{
    @Override
    public void fun1() {
        System.out.println("唱的好听");
    }
}

class Student2 {
     //接口作为参数数据类型,传入实现该接口的类的对象
    public void show(Sing1 sing1){
        sing1.fun1();
    }

}

public class CanShuDemo {
    public static void main(String[] args) {
        Student2 student2 = new Student2();
        //传入对象
        student2.show(new InterImpl());
    }
}

3、今后当你看到一个抽象类作为方法形式参数类型的时候,说明要传入的是继承该抽象类的具体类的子类对象

abstract class People3{
   public abstract void  fun3();
}
class Student3 extends People3{
    @Override
    public void fun3() {
        System.out.println("学习真好!!!");
    }
}
class Student4{
    //、今后当你看到一个抽象类作为方法形式参数类型的时候,
    // 说明要传入的是继承该抽象类的具体类的子类对象
    public void show(People3 people3){
        people3.fun3();
    }
}
public class CanShuDeno2 {
    public static void main(String[] args) {
        Student4 student4 = new Student4();
        // 说明要传入的是继承该抽象类的具体类的子类对象
        student4.show(new Student3());
    }
}

4、返回值:  今后当你看到一个类作为方法的返回值类型的时候,需要返回的是该类或者                                是该类的子类对象

class Teacher2{
    public void fun1(){
        System.out.println("好好学习,天天向上");
    }
}

class Teacher2Demo{
    //今后当你看到一个类作为方法的返回值类型的时候,需要返回的是该类或者是该类的子类对象
    public Teacher2 show1(){
        return new Teacher2();
    }
}



public class FanhuiZhiDemo1 {
    public static void main(String[] args) {
        Teacher2Demo teacher2Demo = new Teacher2Demo();
        Teacher2 teacher2 = teacher2Demo.show1();
        teacher2.fun1();
    }

5、今后当你看到一个接口作为方法的返回值类型的时候,需要返回的是实现该接口的子类对象

//接口
interface Inter5{
    void show1();
}

//实现该接口的类
class Inter5Impl implements Inter5{

    @Override
    public void show1() {
        System.out.println("好好学习,天天向上!");
    }
}

class Teacher3{
    //今后当你看到一个接口作为方法的返回值类型的时候,需要返回的是实现该接口的子类对象
    public Inter5 fun1(){
        return new Inter5Impl();
    }
}

public class FanhuiZhiDemo2 {
    public static void main(String[] args) {
        Teacher3 teacher3 = new Teacher3();
        Inter5 inter5 = teacher3.fun1(); // Inter5 inter5 = new Inter5Impl() 接口多态
        inter5.show1();
    }
}

6、今后当你看到一个抽象类作为方法的返回值类型的时候,需要返回的是继承该抽象类的具体子类对象

abstract class Teacher4{
    public abstract void fun1();
}
//具体的类
class Teacher4Zi extends Teacher4{
    @Override
    public void fun1() {
        System.out.println("今天是下雨天!!");
    }
}
class Teacher4Demo{
    //今后当你看到一个抽象类作为方法的返回值类型的时候,需要返回的是继承该抽象类的具体子类对象
    public Teacher4 show1(){
        return new Teacher4Zi();
    }
}

public class FanhuiZhiDemo3 {
    public static void main(String[] args) {
        Teacher4Demo teacher4Demo = new Teacher4Demo();
        Teacher4 teacher4 = teacher4Demo.show1(); //  Teacher4 teacher4 = new Teacher4Zi()  抽象多态
        teacher4.fun1();
        System.out.println("====================");
        new Teacher4Demo().show1().fun1(); //当调用方法后继续调用方法,这种写代码的方式叫做链式编程 后面在scala语言中常见
    }
}

导包

概述 不同包下的类之间的访问,我们发现,每次使用不同包下的类的时候,都需要加包的全路径。比较麻烦。这个时候,java就提供了导包的功能。

导包格式 import 包名;

注意: 这种方式导入是到类的名称。 虽然可以最后写*,但是不建议。

1、package 要写在Java文件的第一行

2、导包,在所有class之上和package之间写

3、使用别的包下的Demo类
import com.shujia.wyh.day08.ketang.bao1.Demo;

4、如果想要使用某个包下的所有类
import com.shujia.wyh.day08.ketang.bao1.*;

​
package com.shujia.wyh.day08.ketang;

//导包,在所有class之上和package之间写

//使用别的包下的Demo类
import com.shujia.wyh.day08.ketang.bao1.Demo;
import com.shujia.wyh.day08.ketang.bao1.Demo2;

//如果想要使用某个包下的所有类
import com.shujia.wyh.day08.ketang.bao1.*;

​

权限修饰符

publicprotected默认private
同一类中
同一包子类,其他类
不同包子类
不同包其他类

测试代码

public class Power{
    public int a = 11;
    protected int b = 22;
    int c = 33;
    private int d = 44;

    public void fun1(){
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        System.out.println(d);
    }
}
 

类及其组成可以用的修饰符

类: 默认,public,final,abstract 我们自己定义:public居多

成员变量: 四种权限修饰符均可,final,static 我们自己定义:private居多

构造方法: 四种权限修饰符均可,其他不可 我们自己定义:public 居多

成员方法: 四种权限修饰符均可,fianl,static,abstract 我们自己定义:public居多

内部类:把类定义在其他类的内部,这个类就被称为内部类。

内部类的访问特点: 内部类可以直接访问外部类的成员,包括私有。 外部类要访问内部类的成员,必须创建对象。

按照内部类在类中定义的位置不同,可以分为如下两种格式:

 1、成员位置(成员内部类):定义在类中方法外

2、局部位置(局部内部类):定在在类中方法中

一、成员内部类

1、创建对象的语句定义格式

外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();

2、成员内部类可以访问外部类中的所有成员(成员变量、成员方法)。

3、内部类可以加static,但是只能访问静态的成员。

 3、外部类要想访问内部类的成员,就必须在本类中创建内部类的对象。格式为

Inner inner = new Inner();
inner.fun1();

4、其他的类要想访问内部类的成员,要创建该内部类的对象,格式为

外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
Outer.Inner oi1=new Outer().new Inner();

内部类可以加static,但是只能访问静态的成员。如果该内部类为静态的,因为Inner为静态类,所有可以通过类名.的方式去获取

创建对象格式为

Outer.Inner oi2 = new Outer.Inner();
//成员内部类

class Outer{
    int a=10;
    static int b=20;
    final int c=30;
    static int d=40;

    private void show1(){
        System.out.println("你好");
    }

//不产生单独的class文件
//内部类可以加static,只能访问静态的成员b
  class Inner{

        public void fun1(){
            System.out.println(a);
            System.out.println(b);
            System.out.println(c);
            //1、成员内部类可以访问外部类中的所有成员(成员变量、成员方法)
            System.out.println(d);
            show1();
        }
    }

    //3、外部类的成员方法想要使用内部类的成员,就要创建内部类的对象
    public void show2(){
        Inner inner = new Inner();
        inner.fun1();
    }

}
public class InnerDemo {
    public static void main(String[] args) {
     //外部类名称.内部类名称 对象名 = new 外部类名称().new 内部类名称();
//        Outer.Inner oi1=new Outer().new Inner();
        //2、内部类使用内部类的方法
//        oi1.fun1();


        //2、外部类的方法使用内部类的方法
        Outer outer = new Outer();
        outer.show2();


        // 如何在其他类中,使用内部类的成员
        //1、创建内部类的对象,然后调用
        //2、如果内部类是静态的,那么传统的创建内部类的语句失效,那该怎么办?

        //Outer.Inner oi2 = new Outer.Inner();因为Inner为静态类,所有可以通过类名.的方式去获取
        //oi2.fun;
        
    }
}

内部类被静态修饰后的方法有静态和非静态之分。他们的访问和不用静态是不一样的。 访问非静态方法:外部类名.内部类名 对象名 = new 外部类名.内部类名(); 访问静态方法:上面创建的对象访问,或者外部类名.内部类名.方法名();

成员内部类面试题:在控制分别输出:30,20,10

class Outer {
		public int num = 10;
		class Inner {
			public int num = 20;
			public void show() {
				int num = 30;
				System.out.println();
				System.out.println();
				System.out.println();
			}
class Outer2 {
    public int num = 10;

    class Inner {
        public int num = 20;

        public void show() {
            int num = 30;
            System.out.println(num);  // 30
            System.out.println(this.num);  // 20
            System.out.println(Outer2.this.num);  // 10     Outer里面的this
        }
    }

    public void fun1(){
        int num = 100;
        System.out.println(this.num);
    }
}

public class Test1 {
    public static void main(String[] args) {
        Outer2.Inner oi2 = new Outer2().new Inner();
        oi2.show();
    }
}

二、局部内部类

将类定义在成员方法中的类

1、在jdk1.8之后,局部内部类中使用的成员方法中的变量在编译的时候默认会加上final关键字

2、访问内部类的成员:在该方法里面创建内部类的对象,调用内部类的方法。然后在main方法里创建外部类的对象调用fun1方法,就可以访问到局部内部类的成员

class Outer3{
    int a=10;

   public void fun1(){
       int b=20;
        //定义内部类
       class Inner3{
           // a=40;//在jdk1.8之后,局部内部类中使用的成员方法中的变量在编译的时候默认会加上final关键字

           public void show1(){
               System.out.println(a);
           }
       }

       //在方法里面创建内部类的对象,然后创建外部类的对象调用fun1方法,就可以访问到局部内部类的成员
       Inner3 inner3 = new Inner3();
       inner3.show1();
   }



}
public class InnerDemo2 {
    public static void main(String[] args) {
        Outer3 outer3 = new Outer3();
        outer3.fun1();

    }
}

匿名内部类 没有名字的类

前提:存在一个类或者接口 ,这里的类可以是具体类也可以是抽象类。

 当抽象类作为形式参数数据类型,需要传入该抽象类的子类的对象·,因此需要自己去写一个类继承这个抽象类,然后创建这个类的对象。但是用了抽象类就不要自己去写类继承抽象类然后创建对象

语句定义格式:传入该抽象类子类的对象的地方,填上下面的代码。

用这些代码去取代对象,不要再创建别的class文件了

 new 类(抽象类)/接口 () {

      重写方法; } 
/**
   new 类(抽象类)/接口 (){
     重写方法
    }
 当抽象类作为形式参数数据类型,需要传入该抽象类的子类的对象·,因此需要
 自己去写一个类继承这个抽象类,然后创建这个类的对象。
 但是用了抽象类就不要自己去写类继承抽象类然后创建对象
*/
abstract class Student5{

    public abstract void study();
}


class StudentDemo5{
    public void fun1(Student5 student5){
        student5.study();

    }

}
public class NiMingDemo {
    public static void main(String[] args) {
        StudentDemo5 studentDemo5 = new StudentDemo5();
        //匿名内部类
        studentDemo5.fun1(new Student5() {
            @Override
            public void study() {
                System.out.println("我爱唱歌");
            }
        });
    }
}

匿名内部类面试题

按照要求,补齐代码
	interface Inter { void show(); }
	class Outer { //补齐代码 }
	class OuterDemo {
	    public static void main(String[] args) {
		      Outer.method().show();
		  }
	}
要求在控制台输出”HelloWorld”
interface Inner{
    void show();

}
class Outer6{
    public static Inner method(){
        //return 后面应该是实现该接口类的对象
        //一般要定义一个类去实现这个接口然后创建对象
        //此时用匿名类去代替创建,就不要再产生别的class文件了
      return new Inner() {
          @Override
          public void show() {
              System.out.println("helloworld");
          }
      };
    }

}

public class NiMingDemo2 {
    public static void main(String[] args) {
        //Outer可以直接.调用,所以method方法是静态的
        //Outer.method()通过.调用show()方法,只有对象才能调用方法,
        // 说明返回的是一个对象,
        //又发现show方法和接口中的方法一样,说明该对象可以调用接口中的方法,得出返回值类型是接口
        Outer6.method().show();
    }

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值