java笔记-基础概括04

4.继承

继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接 访问父类中的非私有的属性和行为
好处:

  1. 提高代码的复用性。
  2. 类与类之间产生了关系,是多态的前提
    格式:
    通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:
class 父类 { 
...     
 } 
  class 子类 extends 父类 {
 ...      
}
继承后的特点——成员变量

①如果子类父类中出现不重名的成员变量,这时的访问是没有影响的
②如果子类父类中出现重名的成员变量,这时的访问是有影响的
子父类中出现了同名的成员变量时,在子类中需要访问父类中非私有成员变量时,需要使用 super 关键字,修饰 父类成员变量,类似于之前学过的 this 。

public class Fu {
    public String name="父亲";
    private int age;
    public void learn(){
        System.out.println("我正在赚钱....");
    }
}
public class Zi extends Fu {
    private String name="孩子";
    public void play(){
        System.out.println("我正在打篮球....");
        System.out.println(this.name);
        System.out.println(super.name);
    }
}

 public static void main(String[] args) {
        Zi zi = new Zi();
        zi.play();
        zi.learn();
    }
结果为:
我正在打篮球....
孩子
父亲
我正在赚钱....

注意:Fu 类中的成员变量是非私有的,子类中可以直接访问。若Fu 类中的成员变量私有了,子类是不能 直接访问的。通常编码时,我们遵循封装的原则,使用private修饰成员变量,那么如何访问父类的私有成员 变量呢?对!可以在父类中提供公共的getXxx方法和setXxx方法

继承后的特点——成员方法

①成员方法不重名
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。对象调用方法时,会先在子类中查找有没有对 应的方法,若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法
②成员方法重名——重写(Override)
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (Override)。
方法重写 :子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效 果,也称为重写或者复写。声明不变,重新实现

public class Zi extends Fu {
    private String name="孩子";
    public void play(){
        System.out.println("我正在打篮球....");
        System.out.println(this.name);
        System.out.println(super.name);
    }

    @Override
    public void learn() {
        System.out.println("我重写了父亲的方法...");
    }
}

public class test01 {

    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.play();
        zi.learn();
    }

}
结果:
我正在打篮球....
孩子
父亲
我重写了父亲的方法...

注意:

  1. 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
  2. 子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样
继承后的特点——构造方法

1.构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。

  1. 构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构 造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用
public class Fu {
    public String name="父亲";
    private int age;
    public void learn(){
        System.out.println("我正在赚钱....");
    }

    public Fu() {
        System.out.println("fu()");
    }
   
}
public class Zi extends Fu {
    private String name="孩子";
    public void play(){
        System.out.println("我正在打篮球....");
        System.out.println(this.name);
        System.out.println(super.name);
    }

    public Zi() {
        //super();
        System.out.println("zi()");
    }

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

注意:在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空 间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。代码体现在子类的构 造方法调用时,一定先调用父类的构造方法。

继承的特点

① Java只支持单继承,不支持多继承。
②Java支持多层继承(继承体系)
③子类和父类是一种相对的概念

重载

概念:

  • 重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
  • 每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
    重载规则:
  • 被重载的方法必须改变参数列表(参数个数或类型不一样);
  • 被重载的方法可以改变返回类型;
  • 被重载的方法可以改变访问修饰符;
  • 被重载的方法可以声明新的或更广的检查异常;
  • 方法能够在同一个类中或者在一个子类中被重载。
  • 无法以返回值类型作为重载函数的区分标准。
public class OverLoadTest{
    public int test(){
        System.out.println("test1");
        return 1;
    }
 
    public void test(int a){
        System.out.println("test2");
    }   
 
    //以下两个参数类型顺序不同
    public String test(int a,String s){
        System.out.println("test3");
        return "returntest3";
    }   
 
    public String test(String s,int a){
        System.out.println("test4");
        return "returntest4";
    }   
 
    public static void main(String[] args){
        Overloading o = new Overloading();
        System.out.println(o.test());
        o.test(1);
        System.out.println(o.test(1,"test3"));
        System.out.println(o.test("test4",1));
    }
}

重写与重载之间的区别:


重载与重写的区别.PNG

方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式。
(1)方法重载是一个类中定义了多个方法名相同,而他们的参数的数量不同或数量相同而类型和次序不同,则称为方法的重载(Overloading)。
(2)方法重写是在子类存在方法与父类的方法的名字相同,而且参数的个数与类型一样,返回值也一样的方法,就称为重写(Overriding)。
(3)方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现。

5.抽象类

由来:
父类中的方法,被它的子类们重写,子类各自的实现都不尽相同。那么父类的方法声明和方法主体,只有声明还有 意义,而方法主体则没有存在的意义了。我们把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法 的类就是抽象类
定义:

  • 抽象方法 : 没有方法体的方法。
  • 抽象类:包含抽象方法的类
抽象方法

定义格式:

修饰符 abstract 返回值类型 方法名 (参数列表);

示例:

public abstract void run();
抽象类

定义格式:

abstract class 类名字 { }

示例:

public abstract class Animal {
 public abstract void run();
 }

抽象的使用:
继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父 类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。

public class Cat extends Animal {
 public void run (){
 System.out.println("小猫在墙头走~~~");
 }
 }
public class CatTest {
 public static void main(String[] args) { 
// 创建子类对象
 Cat c = new Cat();
 // 调用run方法 c.run();
 } 
}

输出结果:
 小猫在墙头走~~~

此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法。

注意:
1.抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。

  • 理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。

2.抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。

  • 理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。

3.抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。

  • 理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。

4.抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象 类。

  • 理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有 意义。

6.接口

  • 接口,是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法
  • 接口的定义,它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并 不是类,而是另外一种引用数据类型
  • 接口的使用,它不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做 是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象 类
    定义格式 :
 public interface 接口名称 { 
    // 抽象方法 
    // 默认方法
     // 静态方法
     // 私有方法
 }

含有抽象方法:

抽象方法:使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用

public interface InterFaceName { 
    public abstract void method(); 
}

含有默认方法和静态方法

  • 默认方法:使用 default 修饰,不可省略,供子类调用或者子类- - 重写。
  • 静态方法:使用 static 修饰,供接口直接调用
public interface InterFaceName {
     public default void method() {
         // 执行语句
     }  
   public static void method2() {
         // 执行语句
         }
 }

含有私有方法和私有静态方法 :

  • 私有方法:使用 private 修饰,供接口中的默认方法或者静态方法调用
public interface InterFaceName {
     private void method() { 
        // 执行语句 
    }
 }

基本实现:
实现的动作类 似继承,格式相仿,只是关键字不同,实现使用 implements 关键字。

非抽象子类实现接口:

  1. 必须重写接口中所有抽象方法。
  2. 继承了接口的默认方法,即可以直接调用,也可以重写。
    实现格式:
class 类名 implements 接口名 { 
    // 重写接口中抽象方法【必须】
    // 重写接口中默认方法【可选】
    }
抽象方法的使用

必须全部实现,代码如下:
定义接口:

public interface LiveAble { 
// 定义抽象方法
 public abstract void eat();
 public abstract void sleep();
 }

定义实现类:

public class Animal implements LiveAble {
 @Override
 public void eat() { 
System.out.println("吃东西");
 }
@Override
 public void sleep() {
 System.out.println("晚上睡");
 } 
}

定义测试类:

public class InterfaceDemo {
 public static void main(String[] args) { 
// 创建子类对象
 Animal a = new Animal();
 // 调用实现后的方法
 a.eat();
 a.sleep();
 } 
}
输出结果:
 吃东西
 晚上睡
默认方法的使用:

可以继承,可以重写,二选一,但是只能通过实现类的对象来调用。

  1. 继承默认方法,代码如下:
    定义接口:
public interface LiveAble {
 public default void fly(){ 
System.out.println("天上飞");
 }
 }

定义实现类:

public class Animal implements LiveAble { 
// 继承,什么都不用写,直接调用 
}

定义测试类:

public class InterfaceDemo {
 public static void main(String[] args) {
 // 创建子类对象
 Animal a = new Animal();
 // 调用默认方法
 a.fly(); 
  }
}
输出结果:
 天上飞

2.重写默认方法,代码如下:
定义接口:

public interface LiveAble {
 public default void fly(){
 System.out.println("天上飞");
 } 
}

定义实现类:

public class Animal implements LiveAble { 
@Override
 public void fly() { 
System.out.println("自由自在的飞"); 
} 
}

定义测试类:

public class InterfaceDemo { 
public static void main(String[] args) { 
// 创建子类对象
 Animal a = new Animal();
 // 调用重写方法
 a.fly();
 }
 }
输出结果: 
自由自在的飞
静态方法的使用:

静态与.class 文件相关,只能使用接口名调用,不可以通过实现类的类名或者实现类的对象调用,代码如下:
定义接口:

public interface LiveAble {
 public static void run(){ 
System.out.println("跑起来~~~");
 } 
}

定义实现类:

public class Animal implements LiveAble {
// 无法重写静态方法
}

定义测试类:

public class InterfaceDemo {
 public static void main(String[] args) {
 // Animal.run(); 
// 【错误】无法继承方法,也无法调用
 LiveAble.run(); 

} 
}
私有方法的使用:
  • 私有方法:只有默认方法可以调用。
  • 私有静态方法:默认方法和静态方法可以调用。
    如果一个接口中有多个默认方法,并且方法中有重复的内容,那么可以抽取出来,封装到私有方法中,供默认方法 去调用。从设计的角度讲,私有的方法是对默认方法和静态方法的辅助。同学们在已学技术的基础上,可以自行测试。
    定义接口:
public interface LiveAble {
 default void func(){
 func1(); 
func2(); 
}
private void func1(){
 System.out.println("跑起来~~~"); 
}
private void func2(){
 System.out.println("跑起来~~~"); 
} 
}

7.多态

生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也 是不一样的。可见,同一行为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。

定义:

多态: 是指同一行为,具有多个不同表现形式。

前提:
  1. 继承或者实现【二选一】
  2. 方法的重写【意义体现:不重写,无意义】
  3. 父类引用指向子类对象【格式体现】
体现:
父类类型 变量名 = new 子类对象;
变量名.方法名();

父类类型:指子类对象继承的父类类型,或者实现的父接口类型。

Fu f = new Zi(); 
f.method();

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写 后方法。
定义父类:

public abstract class Animal {
       public abstract void eat();   
} 

定义子类:

class Cat extends Animal {
       public void eat() { 
          System.out.println("吃鱼");
       } 
  }     
class Dog extends Animal {
       public void eat() { 
          System.out.println("吃骨头");
       }
   }

定义测试类:

public class Test {
     public static void main(String[] args) {
         // 多态形式,创建对象
         Animal a1 = new Cat();
           // 调用的是 Cat 的 eat 
        a1.eat(); 
                    // 多态形式,创建对象
         Animal a2 = new Dog();
          // 调用的是 Dog 的 eat
         a2.eat(); 
     } 
  }
多态的好处

实际开发的过程中,父类类型作为方法形式参数,传递子类对象给方法,进行方法的调用,更能体现出多态的扩展 性与便利。代码如下:
定义父类:

public abstract class Animal {
       public abstract void eat();
   }

定义子类:

class Cat extends Animal { 
      public void eat() { 
          System.out.println("吃鱼");
       } 
  }     
class Dog extends Animal {
       public void eat() { 
          System.out.println("吃骨头");
       }
   }

定义测试类:

public class Test {
     public static void main(String[] args) {
         // 多态形式,创建对象
         Cat c = new Cat();
         Dog d = new Dog();
          // 调用showCatEat
          showCatEat(c);
         // 调用showDogEat
          showDogEat(d);
            /*  以上两个方法, 均可以被showAnimalEat(Animal a)方法所替代   而执行效果一致*/
         showAnimalEat(c);
         showAnimalEat(d);
      }
       public static void showCatEat (Cat c){
         c.eat();
      } 
      public static void showDogEat (Dog d){ 
        d.eat();
     }
       public static void showAnimalEat (Animal a){
         a.eat();
     }
 }

由于多态特性的支持,showAnimalEat方法的Animal类型,是Cat和Dog的父类类型,父类类型接收子类对象,当 然可以把Cat对象和Dog对象,传递给方法。
当eat方法执行时,多态规定,执行的是子类重写的方法,那么效果自然与showCatEat、showDogEat方法一致, 所以showAnimalEat完全可以替代以上两方法。 不仅仅是替代,在扩展性方面,无论之后再多的子类出现,我们都不需要编写showXxxEat方法了,直接使用 showAnimalEat都可以完成。
所以,多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。

向上转型

多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。
当父类引用指向一个子类对象时,便是向上转型。
使用格式:

父类类型  变量名 = new 子类类型();
 如:Animal a = new Cat();

向下转型

父类类型向子类类型向下转换的过程,这个过程是强制的。
一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。
使用格式:

子类类型 变量名 = (子类类型) 父类变量名;
 如:Cat c =(Cat) a; 
  • 为什么要转型?
    当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥 有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子 类特有的方法,必须做向下转型。

  • 为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:

变量名 instanceof 数据类型  如果变量属于该数据类型,返回true。
 如果变量不属于该数据类型,返回false。

示例:
Animal类:

public abstract   class Animal {
    //抽象方法
    public abstract void run();
    public Animal(){
//        System.out.println("我是Animal");
    }
}

Cat类:

public class Cat extends Animal {


    @Override
    public void run() {
        System.out.println("我是小猫咪,我在跑步....");
    }

    public Cat() {
        super();
    }
    public void eat(){
        System.out.println("chichichichichi");
    }
}

Dog类

public class Dog extends Animal {
    @Override
    public void run() {

    }

    public Dog() {
        System.out.println("我是dog");
    }
    public void watchHouse() {
        System.out.println("看家");
    }
}


测试类:

public static void main(String[] args) {

        public static void main(String[] args) {

        Animal a = new Cat();
        a.run();
        Cat cat = (Cat)a;
        cat.eat();
        //假设忘记我定义了猫咪的方法 ,我向下转型转成dog类可以么?
       // Dog dog = (Dog)a;
        //dog.watchHouse();//报错  ClassCastException 类型转换异常


        if(a instanceof Dog){
            Dog dog = (Dog)a;
            dog.watchHouse();
        }else if(a instanceof Cat){
            Cat cat2 = (Cat)a;
            cat2.eat();
        }
    }
    }
结果:
我是小猫咪,我在跑步....
类型不对....
接口多态的综合案例

笔记本电脑
笔记本电脑(laptop)通常具备使用USB设备的功能。在生产时,笔记本都预留了可以插入USB设备的USB接口, 但具体是什么USB设备,笔记本厂商并不关心,只要符合USB规格的设备都可以。 定义USB接口,具备基本的开启功能和关闭功能。鼠标和键盘要想能在电脑上使用,那么鼠标和键盘也必须遵守 USB规范,实现USB接口,否则鼠标和键盘的生产出来也无法使用。
案例分析:
进行描述笔记本类,实现笔记本使用USB鼠标、USB键盘

  • USB接口,包含开启功能、关闭功能
  • 笔记本类,包含运行功能、关机功能、使用USB设备功能
  • 鼠标类,要实现USB接口,并具备点击的方法
  • 键盘类,要实现USB接口,具备敲击的方法

定义usb接口

public interface USB {
    void open();
    void close();
}

定义鼠标类:

public class Mouse implements USB {
    @Override
    public void open() {
        System.out.println("我是鼠标,我现在是开启状态.....");
    }

    @Override
    public void close() {

    }

    public void click(){
        System.out.println("我是鼠标...我是可以被点击的呀....");
    }
}

定义键盘类:

public class KeyBoard implements USB{
    @Override
    public void open() {
        System.out.println("我是键盘类....我现在正在开启...");
    }

    @Override
    public void close() {
        System.out.println("我是键盘类....我现在正在关闭...");

    }
    public void play(){
        System.out.println("我是键盘类....我是可以被敲打的.......");
    }
}

定义笔记本类:

public class Laptop {
    public void run(){
        System.out.println("我是笔记本,我正在开启");
    }
    public void UseUSB(USB usb){
        if (usb!=null){
            usb.open();
            if(usb instanceof Mouse){
                Mouse mouse = (Mouse)usb;
                mouse.click();
            }else if(usb instanceof KeyBoard){
                KeyBoard keyBoard = (KeyBoard)usb;
                keyBoard.play();
            }
            usb.close();
        }
    }

    public void unrun(){
        System.out.println("我是笔记本,我已经被关闭...");
    }
}

测试类,代码如下:

public class TestLaptop {
    public static void main(String[] args) {
        Laptop laptop = new Laptop();
        laptop.run();
        laptop.UseUSB(new Mouse());
        laptop.UseUSB(new KeyBoard());
        laptop.unrun();
    }
}
结果:
我是笔记本,我正在开启
我是鼠标,我现在是开启状态.....
我是鼠标...我是可以被点击的呀....
我是键盘类....我现在正在开启...
我是键盘类....我是可以被敲打的.......
我是键盘类....我现在正在关闭...
我是笔记本,我已经被关闭...

你可能感兴趣的:(java笔记-基础概括04)