Java笔记 - 黑马程序员_03(继承,修饰符,多态,抽象类,接口,内部类)

1. 继承

1.1 继承的概述

继承是面向对象三大特征之一。可以使得子类具有父类元素的属性和方法,还可以在子类中重新定义,追加属性和方法。

继承的格式:

  • 格式:public class 子类名 extends 父类名

  • 案例:public class ZI extends FU{}

  • FU类为父类(superclass),超类,基类

  • ZI类为子类(subclass),派生类,扩展类

继承中子类的特点:

  • 子类可以有父类的内容

  • 子类也可以有自己特有的内容

//1.创建父类
package extendsDemo;
​
public class Fu {
    public void show(){
        System.out.println("Fu中方法被调用了");
    }
}
​
//2.创建子类(子类继承父类)
package extendsDemo;
​
public class Zi extends Fu{
    public void method(){
        System.out.println("Zi中方法被调用");
    }
}
​
//3.测试类
package extendsDemo;
​
public class Demo {
    public static void main(String[] args) {
        //创建对象,调用方法
        Fu f = new Fu();
        f.show();
​
        Zi z= new Zi();
        z.method();
        z.show();
    }
}
​
//运行结果
Fu中方法被调用了
Zi中方法被调用
Fu中方法被调用了

1.2 继承的好处和弊端

好处:

  • 提高代码的复用性(多个类相同的成员可以放到同一个类中)

  • 提高代码的维护性(如果方法的代码需要修改,修改一处即可)

弊端:

  • 继承让类与类之间产生了关系,类的耦合性增强,当父类发生变化时子类实现也不得不跟着变化,削弱了子类的独立性。

什么时候使用继承?

  • 假设法:有两个类A与B,如果他们之间满足A是B的一种,或者B是A的一种,就说明他们之间存在着继承关系,这个时候他们存在着继承关系,可以考虑使用继承,否则不能滥用继承

  • 例如:苹果和水果,猫和动物(都可使用继承),猫和狗(不能使用继承)

1.3继承中变量的访问

在子类方法中访问一个变量的访问顺序:

  1. 子类局部范围找

  2. 子类成员范围找

  3. 父类成员范围找

  4. 如果都没有就报错(不考虑父类以上的)

//1.
package extendsDemo;
​
public class Fu {
    public int height = 185;
    public int age = 18;
}
​
//2.
package extendsDemo;
​
public class Zi extends Fu{
    public int height = 183;
​
    public void method(){
        int height = 181;
        System.out.println(age);
        //局部变量中的height
        System.out.println(height);
        //this.height访问本类中成员变量中的height
        System.out.println(this.height);
        //super.height访问父类成员变量中的height
        System.out.println(super.height);
    }
}
​
//3.测试类
package extendsDemo;
​
public class Demo {
    public static void main(String[] args) {
        //创建对象,调用方法
        Zi z= new Zi();
        z.method();
    }
}
​
//运行结果
18
181
183
185

1.4 super关键字

super关键字和this关键字的用法相似之处

  • this:代表本类对象的引用(this关键字指向调用该方法的对象)

  • super:代表父类存储空间的标识(可以理解为父类引用对象)

关键字 访问成员变量 访问构造方法 访问成员方法
this this.成员变量 访问本类成员变量 this(.....) 访问本类构造方法 this.成员方法(....) 访问本类成员方法
super super.成员变量 访问父类成员变量 super(.....) 访问父类构造方法 super.成员方法(....) 访问fu类成员方法

1.5 继承中构造方法的访问特点

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

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

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

如果父类没有无参构造方法,只有带参构造方法,该怎么办?

  1. 通过使用super关键字去 显示的调用父类带参构造方法

  2. 在父类中自己提供一个无参构造方法

推荐:自己给出无参构造方法

//1.
package extendsDemo;
​
public class Fu {
 /* public Fu(){
      System.out.println("fu中无参构造方法");
  }*/
​
  public Fu(int age){
      System.out.println("fu中有参构造方法");
  }
}
​
//2.
package extendsDemo;
​
public class Zi extends Fu{
  public Zi(){
//    super();    系统默认调用父类无参构造方法
      super(20);
      System.out.println("zi中无参构造方法");
  }
​
  public Zi(int age){
//    super();    系统默认调用父类无参构造方法
      super(19);
      System.out.println("zi中有参构造方法");
  }
}
​
//3.测试类
package extendsDemo;
​
public class Demo {
    public static void main(String[] args) {
        //创建对象,调用方法
        Zi z= new Zi();
        Zi z1 = new Zi(18);
    }
}
​
//运行结果
fu中有参构造方法
zi中无参构造方法
fu中有参构造方法
zi中有参构造方法

1.6 继承中成员方法的访问特点

通过子类对象访问一个方法:(就近原则)

  1. 子类成员范围找

  2. 父类成员范围找

  3. 如果没有就报错(不考虑父类以上)

//1.
package extendsDemo;
​
public class Fu {
 public void show(){
     System.out.println("fu中的成员方法被调用");
 }
}
​
//2.
package extendsDemo;
​
public class Zi extends Fu {
​
    public void method() {
        System.out.println("Zi中的成员方法被调用");
    }
​
    @Override
    public void show() {
        super.show();   //调用父类的方法
        System.out.println("zi中的成员方法被调用");
    }
}
​
//3.
package extendsDemo;
​
public class Demo {
    public static void main(String[] args) {
        //创建对象,调用方法
        Zi z= new Zi();
        z.show();
        z.method();
    }
}
​
//运行结果
fu中的成员方法被调用
zi中的成员方法被调用
Zi中的成员方法被调用

1.7 super内存图

点击观看视频详解

1.8 方法重写

方法重写概述:

  • 子类中出现了和父类一摸一样的方法声明

方法重写的应用:

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

@Override

  • 是一个注解

  • 可以帮助我们检查重写的方法的 方法声明的正确性

方法重写注意事项:

  • 私有方法不能被重写(父类中private修饰 的不能在子类中 直接访问。可以通过间接的手段来访问。通过get方法来访问)

  • 子类方法的访问权限不能低于父类(public > 默认 > 私有)

//1.
package iphone;
​
public class Iphone {
    public void call(String name){
        System.out.println("给"+name+"打电话");
    }
}
​
//2.
package iphone;
​
public class NewIphone extends Iphone {
    @Override   //帮助我们检查重写的方法的 方法声明的正确性
    public void call(String name) {
        System.out.println("打开视频");
//        System.out.println("给"+name+"打电话");
        super.call(name);
    }
}
​
//3.
package iphone;
​
public class IphoneDemo {
    public static void main(String[] args) {
        Iphone p = new Iphone();
        p.call("张三");
        System.out.println("-------------");
​
        NewIphone np = new NewIphone();
        np.call("李四");
​
    }
}
​
//运行结果
给张三打电话
-------------
打开视频
给李四打电话

1.10 Java中继承的注意事项

  1. Java中类只支持单继承,不支持多继承

  2. Java支持多层继承(间接继承)

        例如:class C extends B,class B extends A,

        也就 是说,C 直接继承 B,其实 C 还间接继承 A

1.11 案例

1. 老师和学生

需求:定义老师类和学生类,找到老师类和学生类的共性内容,抽取一个父类,用继承的方式改写代码,并进行测试

思路:

  1. 共性父类,定义人类(姓名, 年龄)

  2. 定义老师类,继承人类,给出自己的方法:教书()

  3. 定义老师类,继承人类,给出自己的方法:学习()

  4. 定义测试类,写代码测试

//1.定义老师类
package studentAndTeacher;
​
public class Teacher extends Person {
​
    public Teacher() {
    }
​
    public Teacher(String name, int age) {
      /*  this.name = name;
        this.age = age;*/
        super(name, age);//通过super()访问父类的带参构造方法
    }
​
    public static void teach() {
        System.out.println("正在教书");
    }
}
​
//2.定义学生类
package studentAndTeacher;
​
public class Student extends Person {
​
    public Student() {
    }
​
    public Student(String name, int age) {
        /*this.name = name;
        this.age = age; 其他类不能访问公共类的私有成员*/
        super(name, age);//通过super()访问父类的带参构造方法
    }
​
    public static void stud() {
        System.out.println("正在学习");
    }
}
​
//3.定义公共类
package studentAndTeacher;
​
public class Person {
    private String name;
    private int age;
​
    public Person() {
    }
​
    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 static void dos(String ds){  //定义公共方法
        System.out.println(ds);
    }
}
​
//4.测试类
package studentAndTeacher;
​
public class Demo {
    public static void main(String[] args) {
​
        Student sc = new Student("张三",18);
        System.out.println(sc.getAge()+", "+sc.getName());
        sc.stud();
        sc.dos("学习");
​
        Teacher cc = new Teacher("李四",25);
        System.out.println(cc.getAge()+", "+cc.getName());
        cc.teach();
        cc.dos("教书");
    }
}
​
//运行结果
18, 张三
正在学习
学习
25, 李四
正在教书
教书

2.猫和狗

需求:采用继承的思想实现猫和狗的案例,并在测试类中进行测试

共性:

成员变量:姓名,年龄;构造方法:无参,带参;成员方法:get/set方法

//1.
package catAndDog;
​
public class Cat extends Animal {
    public Cat() {
    }
​
    public Cat(String name, int age) {
        super(name, age);   //调用父
    }
​
    public static void show(){
        System.out.println("抓老鼠");
    }
}
​
//2.package catAndDog;
​
public class Dog extends Animal {
    public Dog() {
    }
​
    public Dog(String name, int age) {
        super(name, age);
    }
​
    public static void method(){
        System.out.println("看家");
    }
}
​
//3.
package catAndDog;
​
public class Animal {
    private String name;
    private int age;
​
    public Animal() {
    }
    public Animal(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 static void fn(String dos){
        System.out.println(dos);
    }
}
​
//4.
package catAndDog;
​
public class Demo {
    public static void main(String[] args) {
        Dog an = new Dog("ww",2);
        System.out.println(an.getName()+", "+an.getAge());
        an.method();
        an.fn("看门");
​
        Cat ca = new Cat("mm",1);
        System.out.println(ca.getName()+", "+ca.getAge());
        ca.show();
        ca.fn("抓小鸡");
    }
}
​
//运行结果
ww, 2
看家
看门
mm, 1
抓老鼠
抓小鸡

2. 修饰符

2.1包的概述和使用

其实就是文件夹 作用:对类进行分类管理 包的定义格式

  1. 格式:package包名; (多级包用分开)

  2. 范例:package com.itheima; 带包的)ava类编译和执行

手动建包:

1.按照以前的格式编译java文件                 javac HelloWorld.java

2.手动创建包                 在E盘建立文件夹com,然后在com下建立文件夹theima

3.把class文件放到包的最里面             把HelloWorld.class文件放到com下的Jitheimai这个文件夹下

4.带包执行                 java com.itheima.HelloWorld

自动建包:

javac-d,HelloWorld.java                 java com.itheima.HelloWorld

2.2导包的概述和使用

使用不同包下的类时,使用的时候要写类的全路径,写起来太麻烦了 为了简化带包的操作,Jva就提供了导包的功能

导包的格式:

1. 格试:import包名:

2. 范例:import cn.itcast..Teacher

为了简化带包的操作,Jva就提供了导包的功能

导包的格式

格试:import  包名:

  • 范例:importcn.itcast.Teacher

2.3 修饰符权限

修饰符 同一个类中 同一个包中子类无关类 不同包的子类 不同包的无关类
private yes no no no
默认 yes yes no no
protected yes yes yes no
public yes yes yes yes

2.4 final

final关键字是最终的意思,可以修饰成员方法,成员变量,类

final修饰的特点:

  • 修饰方法:表明该方法是最终的方法,不能被重写

  • 修饰变量:表明该变量是常量,不能再次被赋值

  • 修饰类:表明该类是最终类,不能被继承

final修饰局部变量

  • 变量是基本类型:final修饰指的是基本类型的数据值不能发生改变

  • 变量是引用类型:final修饰指的是引用类型的地址值不能发生改变,但是地址里面的内容是可以改变的

//1.
package finalDemo;
​
public class Student {
    public int age = 18;
}
​
//2.
package finalDemo;
​
import org.w3c.dom.ls.LSOutput;
​
public class FinalDemo {
    public static void main(String[] args) {
        //final修饰基本变量
        final int age = 20;
//        age = 18;     报错
        System.out.println(age);
​
        //final修饰引用类型变量
        final Student s = new Student();
        s.age = 20;
        System.out.println(s.age);
    }
}

代码块 -- new

代码块概述:

  • 代码块是类的成分之一(成员变量、构造器,方法,代码块,内部类Java类中,使用{ }括起来的代码被称为代码块。

  • 在Java类中,使用{}括起来的代码被称为代码块。

代码块分为:

  • 构造代码块

    1. 格式:{}

    2. 特点:每次构造方法执行之前,都会先执行构造代码块的代码。

    3. 使用场景:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性。 静态代码块

  • 静态的代码块

    1. 格式:static{}

    2. 特点:随着类的加载而触发执行,并且只会执行一次。

    3. 使用场景:在类加载的时候做一些静态数据初始化的操作,以便后续对象可以使用。

package com.demo;
​
public class Demo_代码块 {
​
    //每次构造方法执行之前,都会先执行构造代码块的代码
    //没有构造方法不会出发执行构造代码块
    {
        System.out.println("构造代码块");
    }
    //随着类的加载而触发执行,并且只会执行一次
    static  {
        System.out.println("静态代码块");
    }
}

2.5 static

static关键字是静态的意思,可以修饰成员变量,成员方法

static修饰的特点:

  • 被类的所有对象共享;这是判断是否使用静态关键字的条件

  • 可以通过类名调用;也可以通过对象名调用;推荐使用类名调用

2.6 static访问特点

非静态成员方法:

  • 能访问静态的成员变量

  • 能访问非静态的成员变量

  • 能访问静态的成员方法

  • 能访问非静态的成员方法

静态成员方法:

  • 能访问静态成员变量

  • 能访问静态成员方法

总结:静态成员方法只能访问静态成员

3. 多态

3.1 多态的概述

  • 同一个对象,在不同时刻表现出来的不同形态

  • 多种形态,多种状态,编译和运行有两个不同的状态。

    编译期叫做静态绑定。

    运行期叫做动态绑定。

  • Animal a = new Cat();

        1. a.eat();

        2. 父类引用指向子类对象

        3. 编译的时候编译器发现a的类型是Animal,所以编译器会去Animal类中找eat()方法

        4. 找到了,绑定,编译通过。但是运行的时候和底层堆内存当中的实际对象有关

        5. 真正执行的时候会自动调用“堆内存中真实对象”的相关方法。

多态在开发中的作用是: 降低程序的耦合度,提高程序的扩展力。

多态的前提和实现:

  1. 有继承/实现关系

  2. 有方法重写

  3. 有父类引用指向子类对象

3.2 多态中成员访问特点

成员变量:编译看左边,执行看左边

成员方法:编译看左边,执行看右边

为什么成员变量和成员方法不一样?

  • 因为成员方法有重写,成员变量没有

3.3 多态的好处和弊端

  • 多态的好处:提高程序的扩展性

具体体现:定义方法的时候,使用父类型作为参数,将来使用的时候,使用具体的子类型参与操作

  • 多态的弊端:不能使用子类的特有功能

3.4 多态中的转型

向上转型:子--->父 (upcasting) 又被称为自动类型转换:Animal a = new Cat();

向下转型:父--->子 (downcasting) 又被称为强制类型转换:Cat c = (Cat)a; 需要添加强制类型转换符。

什么时候需要向下转型?

1.需要调用或者执行子类对象中特有的方法。

2.必须进行向下转型,才可以调用。

向下转型有风险吗?

1.容易出现ClassCastException(类型转换异常)

怎么避免这个风险?

1. instanceof运算符,可以在程序运行阶段动态的判断某个引用指向的对象是否为某一种类型。

不管是向上转型还是向下转型,首先他们之间必须有继承关系,这样编译器就不会报错。

//1.
package demo_01;
​
public class Animal {
    public void eat(){
        System.out.println("吃东西");
    }
}
​
//2.
package demo_01;
​
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
    public void show(){
        System.out.println("猫捉老鼠");
    }
}
​
//3.测试类
package demo_01;
​
public class AnimalDemo {
    public static void main(String[] args) {
        //父类引用指向子类对象
        Animal a = new Cat();
        a.eat();
// 报错       a.show();
        //向下转型
        Cat b = (Cat)a;
        b.eat();
        b.show();
    }
}
3.5 猫和狗(多态版)
//1.
package catAndDog;
​
public class Animal {
    private String name;
    private int age;
​
    public Animal() {
    }
​
    public Animal(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 void eat(){
        System.out.println("吃东西");
    }
}
​
//2.
package catAndDog;
​
public class Dog extends Animal{
    public Dog() {
    }
​
    public Dog(String name, int age) {
        super(name, age);
    }
​
    @Override
    public void eat() {
        System.out.println("饿狗扑食");
    }
​
    public void show(){
        System.out.println("小狗玩耍");
    }
}
​
//3.测试类
package catAndDog;
​
import demo_01.Cat;
​
public class AnimalDemo {
    public static void main(String[] args) {
        //父类引用指向子类对象,创建对象
        Animal a = new Dog("小黄", 6);
        a.eat();
//        a.show(); 报错
        System.out.println("--------------");
​
        //向下转型
        Dog d = (Dog) a;
        d.eat();
        d.show();
        System.out.println("--------------");
​
       /* Dog s = new Dog("小红", 2);
        s.show();
        s.eat();*/
    }
}
​
//运行结果
饿狗扑食
--------------
饿狗扑食
小狗玩耍
--------------

4. 抽象类

4.1 抽象类的概念

在Java中,一个没有方法体的方法应该定义为抽象方法,而类中的如果有抽象方法,该类必须定义为抽象类

package demo_01;
​
public abstract class Animal {
​
    public abstract void eat();
​
}

4.2 抽象类的特点

  • 抽象类和抽象方法必须用abstract关键字修饰 

public abstract class 类名{}

public abstract void eat();

  • 抽象类不一定有抽象方法,有抽象方法的类一定是抽象类

  • 抽象类不能实例化

抽象类如何实例化呢?参照多态的形式,通过子类对象实例化,这叫抽象类多态

  • 抽象的子类

1.要么重写抽象类中的所有抽象方法

2.要么是抽象类

4.3 抽象类的成员特点

  • 成员变量

可以是变量

也可以是常量

  • 构造方法

有构造方法,但不能实例化

构造方法的作用是什么呢?用于子类访问父类数据的初始化

  • 成员方法

可以有抽象方法:限定子类必须完成某些动作

也可以有非抽象方法:提高代码复用性

4.4 猫和狗(抽象类版)

需求:采用抽象类的思想实现猫和狗的案例,并在测试类中进行测试

//1.定义抽象类
package catAndDog;
​
public abstract class Animal {
    private String name;
    private int age;
​
    public Animal() {
    }
​
    public Animal(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 eat();
}
​
//2.
package catAndDog;
​
public class Cat extends Animal{
    public Cat() {
    }
​
    public Cat(String name, int age) {
        super(name, age);
    }
​
    @Override
    public void eat() {
        System.out.println("小猫吃鱼");
    }
​
    public void show(){
        System.out.println("66666666");
    }
}
​
//3.测试类
package catAndDog;
​
public class AnimalDemo {
    public static void main(String[] args) {
        Animal a = new Cat();
        a.setName("大菊");
        a.setAge(2);
        System.out.println(a.getName() + ", " + a.getAge());
        a.eat();
        System.out.println("--------------");
​
        a = new Cat("小黄", 3);
        System.out.println(a.getName() + ", " + a.getAge());
        a.eat();
        System.out.println("--------------");
​
        Cat b = (Cat) a;
        b.show();
    }
}
​
//运行结果
大菊, 2
小猫吃鱼
--------------
小黄, 3
小猫吃鱼
--------------
66666666

5. 接口

5.1 接口概述

  • 接口就是一种公共的规范标识,只要符合标准规范,大家可以共享

  • Java中的接口更多体现在对行为的抽象

5.2 接口的特点

  • 接口用关键字interface修饰

public interface 接口名{}

  • 类实现接口implements接口名{}

public class 类名 implements 接口名{}

  • 接口不能实例化

1.接口如何实例化? 参照多态的方式,通过实现子类对象实例化,这叫接口实例化

2.多态的形式:具体类多态, 抽象类多态接口多态

  • 接口实现类

1.要么重写接口中的所有抽象方法

2.要么是抽象类

5.3 接口成员的特点

  • 成员变量

只能是常量

默认修饰符:public static final(可省略)

  • 构造方法

1. 接口没有构造方法,因为接口主要是对行为进行抽象的,是没有具体存在的

2. 一个类如果没有父类,默认继承Object

  • 成员方法

    1. 只能是抽象方法

    2. 默认修饰符:public abstract

5.4 猫和狗(接口版)

需求:对猫和狗进行训练,他们就可以调高,这里加入了调高功能,请采用抽象类和接口来实现猫和狗案例

//1.定义接口
package catAndDog;
​
public interface Jumpping {
    public abstract void jump();
}
​
//2.定义动物类
package catAndDog;
​
public abstract class Animal {
    private String namne;
    private int age;
​
    public Animal() {
    }
​
    public Animal(String namne, int age) {
        this.namne = namne;
        this.age = age;
    }
​
    public String getNamne() {
        return namne;
    }
​
    public void setNamne(String namne) {
        this.namne = namne;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    public abstract void eat();
}
​
//3.定义猫类
package catAndDog;
​
public class Cat extends Animal implements Jumpping{
    public Cat() {
    }
​
    public Cat(String namne, int age) {
        super(namne, age);
    }
​
    @Override
    public void eat() {
        System.out.println("小猫吃鱼");
    }
​
    @Override
    public void jump() {
        System.out.println("小猫跳高");
    }
}
​
//4.测试类
package catAndDog;
​
public class AnimalDemo {
    public static void main(String[] args) {
        Jumpping j = new Cat();
        j.jump();
        System.out.println("--------------");
​
        Animal a = new Cat("加菲猫", 3);
        System.out.println(a.getNamne() + ", " + a.getAge());
        a.eat();
//        a.jump();     报错
        System.out.println("--------------");
​
        a = new Cat("大菊", 2);
        System.out.println(a.getNamne() + ", " + a.getAge());
        a.eat();
    }
​
}
​
//运行结果
小猫跳高
--------------
加菲猫, 3
小猫吃鱼
--------------
大菊, 2
小猫吃鱼

5.5 类和接口的关系

  • 类和类的关系

继承关系,只能单继承,但是可以多层继承

  • 类和接口的关系

实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口

  • 接口和接口的关系

继承关系,可以单继承,也可以多继承

//接口1
package Demo_02;
​
public interface Inter1 {
}
​
//接口2
package Demo_02;
​
public interface Inter2 {
}
​
//接口3
package Demo_02;
​
public interface Inter3 extends Inter1, Inter2 {
    //接口和接口的关系
}
​
//创建类
package Demo_02;
​
public class Demo extends Object implements Inter1,Inter2{
    //类和接口的关系(继承Object,体现Inter1,Inter2)
}

5.6 抽象类和接口的区别

  • 成员区别

抽象类:变量,常量;有构造方法;有抽象方法,也有非抽象方法

接口:常量,抽象方法

  • 关系区别

类与类:继承,单继承

类与接口:实现,可以单实现,也可以多实现

接口与接口:继承,单继承,多继承

  • 设计理念区别

抽象类:对类抽象,包括属性和行为

接口:对行为抽象,主要是行为

//1.定义接口
package Demo_02;
​
public interface Inter1 {
    void jump();
}
​
//2.定义猫类
package Demo_02;
​
public abstract class Cat {
    public abstract void eat();
}
​
//3.测试类
package Demo_02;
​
public class Demo extends Cat implements Inter1{
    @Override
    public void jump() {
        //方法体
    }
​
    @Override
    public void eat() {
        //方法体
    }
}

2.接口组成更新概述

2.1接口组成

常量    public  static final
 抽象方法    public abstract
默认方法(Java8)
静态方法(Java8)
私有方法(Java9)

2.2接口中默认方法

接口中默认方法的定义格式:

- 格式:public default  返回值类型方法名(参数列表){}
- 范例:public default void show(){}

接口中默认方法的注意事项:

- 默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字
- public可以省略,default不能省略

```java
package demo_01;

public interface MyInterface {
    void show1();
    void show2();
    //接口中默认方法
    public default void show3(){
        System.out.println("MyInterface的私有方法");
    }
}
```

2.3接口中静态方法

接口中静态方法的定义格式:

- 格式:public static  返回值类型方法名(参数列表){}
- 范例:public static void show(){}

接口中静态方法的注意事项:

- 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用
- public可以省略,static不能省略

```java
package demo_01;

public interface MyInterface {
    void show1();
    void show2();
    
    //接口中的静态方法(静态方法只能通过接口名调用 MyInterface.show4())
    public static void show4(){
        System.out.println("MyInterface的静态方法");
    }
}

```

2.4 接口中的私有方法

接口中私有方法的定义格式:

- 格式1:private返回值类型方法名(参数列表){}
- 范例1:private void show() {}
- 格式2:private static 返回值类型方法名(参数列表){}
- 范例2:private static void method(){}

接口中私有方法的注意事项:

- 默认方法可以调用私有的静态方法和非静态方法
- 静态方法只能调用私有的静态方法

```java
package demo_01;

public interface MyInterface {
    void show1();
    void show2();

    public default void show3(){
//        System.out.println("初级程序员");
//        System.out.println("中级程序员");
//        System.out.println("高级程序员");
        show5();
    }

    public static void show4(){
//        System.out.println("初级程序员");
//        System.out.println("中级程序员");
//        System.out.println("高级程序员");
        show5();
    }
    //接口中的私有方法
    private static void show5(){
        System.out.println("初级程序员");
        System.out.println("中级程序员");
        System.out.println("高级程序员");
    }
}
```

6. 形参和返回值

6.1 类名作为形参和返回值

  • 方法的形参是类名,其实需要的是该类的对象

  • 方法的返回值类名,其实返回的是该类的对象

//1.定义猫类
package demo_03;
​
public class Cat {
    public void eat(){
        System.out.println("猫吃鱼");
    }
}
​
//2.定义猫类操作类
package demo_03;
​
public class CatOperator {
    public void usecat(Cat c){  //传递过来的参数为 Cat c = new Cat();
        c.eat();
    }
​
    public Cat method(){
        Cat b = new Cat();
        return b;
    }
}
​
//3.测试类
package demo_03;
/*
方法的形参是类名,其实需要的是该类的对象
方法的返回值类名,其实返回的是该类的对象
 */
public class CatDemo {
    public static void main(String[] args) {
        CatOperator op = new CatOperator();
        Cat c = new Cat();
        op.usecat(c);
​
        Cat a = op.method();    //  返回值为new Cat对象
        a.eat();
    }
}
//4.运行结果
猫吃鱼
猫吃鱼

6.2 抽象类名作为形参和返回值

  • 方法的形参是抽象类名,其实需要的是该抽象类的子类对象

  • 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象

//1.
package Demo_04;
​
public abstract class Animal {
    public abstract void eat();
}
​
//2.
package Demo_04;
​
public class AnimalOperator {
    public void show(Animal a){ //Animal c = new Cat();
        a.eat();
    }
​
    public Animal method(){ //return new Cat();
        Animal b= new Cat();
        return b;
    }
}
​
//3.定义猫类,创建Animal抽象类子类对象
package Demo_04;
​
public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
​
//4.测试类
package Demo_04;
​
public class AnimalDemo {
    public static void main(String[] args) {
        AnimalOperator s = new AnimalOperator();
        Animal c = new Cat();
        s.show(c);
​
        Animal m = s.method();
        m.eat();
​
    }
}
//4.运行结果
猫吃鱼
猫吃鱼

6.3 接口名作为形参和返回值

  • 方法的形参是接口名,其实需要的是该接口的实现类对象

  • 方法的返回值是接口名,其实返回的是该接口的实现类对象

//1.
package Demo_05;
​
public interface Jumpping {
    void jump();
}
​
//2.
package Demo_05;
​
import Demo_01.Jump;
​
public class JumppingOperator {
    public void show(Jumpping a){
        a.jump();
    }
​
    public Jumpping method(){
        Jumpping b= new Cat();
        return b;
    }
}
​
//3.
package Demo_05;
​
public class Cat implements Jumpping{
    @Override
    public void jump() {
        System.out.println("猫跳高");
    }
}
​
//4.
package Demo_05;
/*
- 方法的形参是接口名,其实需要的是该接口的实现类对象
- 方法的返回值是接口名,其实返回的是高接口的实现类对象
 */
public class JumppingDemo {
    public static void main(String[] args) {
        //创建操作类对象,调用方法
        JumppingOperator j = new JumppingOperator();
        Jumpping s = new Cat();
        j.show(s);
​
        Jumpping m = j.method();
        m.jump();
​
    }
}
//5.运行结果
猫跳高
猫跳高

7. 内部类

7.1 内部类概述

  • 内部类:就是在一个类中定义一个类。

  • 举例:在一个类A的内部定义一个类B,类B就被称为内部类

  • 内部类的定义格式

    1. 格式:

      public class 类名{

      修饰符 class 类名{

      }

      }

  • 内部类的访问特点:

  1. 内部类可以访问外部类的成员,包括私有

  2. 外部类要访问内部类的成员,必须创建对象

//1.定义类
package demo_01;
/*
内部类的访问特点:
1. 内部类可以访问外部类的成员,包括私有
2. 外部类要访问内部类的成员,必须创建对象
*/
public class Outer {
    private int age = 18;
    public class Inner{
        public void show(){
            //内部类中访问外部类中的成员变量
            System.out.println(age);
        }
    }
    public void method(){
        Inner a = new Inner();
        a.show();
    }
}
​
//2.测试类
package demo_01;
​
public class OuterDemo {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.method();
    }
}
//运行结果
18

7.2 成员内部类

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

  • 在类的成员位置:成员内部类(在成员变量定义的类)

  • 在类的局部位置:局部内部类(在方法中定义的类)

成员内部类,外界如何使用呢?

  • 格式:外部类名.内部类名 对象明 = 外部类对象.内部类对象

  • 范例:Outer.Inner oi = new Outer().new Inner();

局部内部类:

  • 局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用,该类可以直接访问外部类的成员,也可以访问的方法内的局部变量

//1.
package demo_01;
​
public class Outer {
    private int age = 18;
    //成员内部类
    public class Inner {
        public void show() {
            System.out.println(age);
        }
    }
​
    //局部内部类
    public void method() {
        int age2 = 20;
        class Inner {
            public void show() {
                System.out.println(age);
                System.out.println(age2);
            }
        }
        Inner i = new Inner();
        i.show();
    }
}
​
//2.
package demo_01;
​
public class OuterDemo {
    public static void main(String[] args) {
        //创建成员内部类对象并调用
        Outer.Inner oi = new Outer().new Inner();
        oi.show();
        System.out.println("-----------");
        //创建对象,调用成员内部类
        Outer o = new Outer();
        o.method();
    }
}
//运行结果
18
-----------
18
20

7.3 匿名内部类

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

  • 格式:

new 类名或者接口名(){

重写方法;

};

  • 范例:

new Inter(){

public void show(){

}

};

  • 本质:是一个继承了该类或者实现了该接口的子类匿名对象

//1.定义接口
package demo_02;
​
public interface Inter {
    void show();
}
​
//2.
package demo_02;
/*
本质:是一个继承了该类或者实现了该接口的子类匿名对象
*/
public class Outer{
​
    public void method(){
        /*
        new Inter(){
            @Override
            public void show() {
                System.out.println("匿名内部类");
            }
        };
        */
​
       /*
       new Inter(){     //匿名内部类
           @Override
           public void show() {
               System.out.println("匿名内部类");
           }
       }.show();    //对象可以直接调用方法
       */
​
        Inter i = new Inter(){  
            //接口不能创建对象,但这里是根据匿名对象创建对象,匿名对象已经将方法重写了,相当于是接口的实现类,用接口的实现类创建对象就没有什么问题了
            @Override
            public void show() {
                System.out.println("匿名内部类");
            }
        };
        i.show();
        i.show();
​
   }
}
​
//3.测试类
package demo_02;
​
public class OuterDemo {
    public static void main(String[] args) {
        Outer o = new Outer();
        o.method();
    }
}
​
//4.运行结果
匿名内部类
匿名内部类

7.4 匿名内部类在开发中的使用

//1.跳高接口
package Demo_03;
//
public interface Jumpping {
    void jump();
}
​
//2.接口操作类,里面有一个方法,方法的参数是接口名
package Demo_03;
​
public class JumppingOpertor {
    public void method(Jumpping j){
        j.jump();
    }
}
​
//3.接口实现类
package Demo_03;
​
public class Cat implements Jumpping{
    @Override
    public void jump() {
        System.out.println("小猫跳高了");
    }
}
​
//4.测试类
package Demo_03;
​
public class JumppingDemo {
    public static void main(String[] args) {
        //创建接口操作类对象,调用method方法
        JumppingOpertor s = new JumppingOpertor();
        Jumpping c = new Cat();
        s.method(c);
        System.out.println("-----------");
​
        //匿名函数作为参数调用方法(好处:不需要在d接口实现类)
        s.method(new Jumpping() {
            @Override
            public void jump() {
                System.out.println("小狗跳高");
            }
        });
​
    }
}
​
//运行结果
小猫跳高了
-----------
小狗跳高

冒泡排序

排序:将一组数据按照固定的规则进行排列

  • 冒泡排序:一种排序的方式,对要进行排序的数据中相邻的数据进行两两比较,将较大的数据放在后面,依次对所有的数据进行操作,直至所有数据按要求完成排序

  • 如果有n个数据进行排序,总共需要比较n-1次

  • 每一次比较完毕,下一次的比较就会少一个数据参与

package test;
​
public class MaoPaoDemo {
    public static void main(String[] args) {
        int[] arr = {52, 66, 42, 88, 33};
        String c = arrayToString(arr);
        System.out.println("排序前:"+c);
​
        /*
        如果有n个数据进行排序,总共需要比较n-1次
        每一次比较完毕,下一次的比较就会少一个数据参与
        */
        for (int x = 0; x < arr.length - 1; x++) {
            for (int i = 0; i < arr.length - 1 - x; i++) {
                if (arr[i] > arr[i + 1]) {
                    int temp = arr[i];
                    arr[i] = arr[i + 1];
                    arr[i + 1] = temp;
                }
            }
        }
        System.out.println("排序后:"+arrayToString(arr));
    }
​
​
    //把数组中的元素按照指定的规则组成一个字符串
    public static String arrayToString(int[] arr) {
        StringBuilder s = new StringBuilder();
        s.append("[");
        for (int i = 0; i < arr.length; i++) {
            if (i == arr.length - 1) {
                s.append(arr[i]);
            } else {
                s.append(arr[i]).append(",");
            }
        }
        s.append("]");
        return s.toString();
    }
}
//运行结果
排序前:[52,66,42,88,33]
排序后:[33,42,52,66,88]

更多内容请访问博主博客:逸乐的博客 - 今晚一起吃火锅

文章如有纰漏请指出,整理不易多多包涵。

Java后续笔记将持续更新........

你可能感兴趣的:(Java,java,idea)