Java教程

03Java面向对象

本文主要是介绍03Java面向对象,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

面向过程和面向对象的设计思想

面向过程:是一种程序设计思想。C语言

​ 解决问题时,是按具体的实现步骤一步一步实现。

​ 面向过程直接关注流程。

​ eg. 首先 开门()

​ 其次 装大象()

​ 最后 关门()

面向对象:是一种程序设计思想。Java、Python,C++,C#

​ 以分类的方式进行思考和解决问题。

​ 先对整体关系进行分类,根据不同的类深入细节的处理。

符合人类认知习惯。

  • 面向对象 —> 使用对象 对象是什么 对象从何而来

  • 面向对象实现:对客观事物进行分类(设计类/发现类 类是抽象的),实际使用时,需要以类为模板创建出一 个个具体的对象。

    人类 —> 张三(对象)

    设计一个冰箱类(抽象的)

    public class 冰箱{

    ​ 名字

    ​ 型号

    ​ 价格

    ​ 开门();

    ​ 装大象;

    ​ 关门();

    }

    冰箱 bx = new 冰箱(); //bx表示这个对象,在运行时在内存中会划出一块空间,用来存储具体的对象。

    bx.开门(); //具体的对象

    冰箱.开门(); //错误 冰箱是一个概念

面向对象是在宏观整体上对事物之间的关系进行设计,具体实现又回归到面向过程的具体实现,两者是相辅相成的。

什么是类

类是一个模板,是对同一类事物属性(名词)和行为(动词)的抽象。

类是有地址的,包就是其地址。

类是一个模板,它是

类的结构:

  • 成员变量:事物属性的描述。名词 属性

    成员变量在定义是,可以对其初始化,也可以不进行初始化,java会在构造方法中对其进行默认赋值 。 引用类型值为:null int:0 float:0.0 char:‘ ’ boolean:false

    局部变量需要自己对其初始化。

    创建对象时,会从类中向对象中复制一份成员变量 到对象中

    成员变量可以被 方法,构造方法,代码块所访问

  • 成员方法:事物的行为。(可以做的事情) 动词 行为

  • 构造方法:初始化对象。 有专职作用 初始化对象

  • 内部类:即在类体中声明的类。

  • 代码块:一段没有名称的代码。

类的定义:

  • 发现类
  • 发现类的共有属性(成员变量)
  • 发现类的方法

以类为模板创建对象 使用对象。

万事万物(实际存在的事物 具体) 皆为对象

//Car.java

/*发现类  汽车类
* public(访问权限修饰符)  class(关键字修饰类)  Car(类名)
* {
*      类体
*      成员变量
*      成员方法
*      构造方法
* }*/
public class Car {
    /*
        定义类的成员变量   名词  属性
        直接定义在类中,所以成为类的成员
        可以使用java所支持的任意的数据类型   基本类型、引用类型
    */
    String name;  //引用类型
    String color;
    float price;  //基本类型

    /*
        定义类的成员方法   动词  行为
    */
    public void run(){
        System.out.println(this.name+"汽车行驶");
    }

    public void stop(){
        System.out.println(name+"汽车停止");
    }

}

什么是对象

对象是类的一个实例,是以类为模板在内存中创建的实际存在的实例。

//TestCar.java

public class TestCar {
    public static void main(String[] args) {
        /*
            类是模板,是抽象概念  就是一个定义
            对象是具体,可以直接被使用的,是以类为模板,在内存中创建出来的实际存在的实例
        */
        Car bm = new Car();
        bm.name = "宝马";
        bm.color = "黑色";
        bm.price = 200000;
        System.out.println(bm.name);
        bm.run();
        bm.stop();

        Car bc = new Car();
        bc.name = "奔驰";
        bc.color = "黑色";
        bc.price = 2043000;
        System.out.println(bc.name);
        bc.run();
        bc.stop();
    }
}

对象的创建和使用:

  • Car bm = new Car();

  • Car() 构造方法 构造方法的名字与类名相同new Car() new 关键字,创建对象。

    以Car类为模板,在内存中创建一个具体实例 将类这个模板中的成员向具体对象中复制一份,每个对象中都是独一无二的。

  • Car bm/bc 声明了一个类型为Car的变量 。

  • = 将右边的对象地址赋值给左边的变量,左边的变量就在程序中表示内存中的对象。

  • 同一类的每个对象有不同的成员变量存储空间。

  • 同一类的每个对象共享该类的方法。

类和对象

类是一类事物的抽象概念,是一个模型。

对象是由这个模型所创造的一个个具体存在的,实实在在存在的实例。所以创建对象的过程也叫实例化对象。

现实生活中先有对象后有类,而编程时先设计类后创建对象。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T07lZ2qF-1642687013926)(E:\Java学习\2022-1-16java第三章面向对象1\课件\创建对象简图.png)]

构造方法

特点:构造方法名与类名相同,且没有返回值,且不需要void修饰。

作用:在构造方法中为创建的对象初始化赋值。

每次创建对象时,至少要调用一个构造方法,一个类中可以有多个构造方法

每个类都有构造方法。如果没有显式地为类定义构造方法,Java将会为该类提供一个默认构造方法,但是只要在一个Java类中定义了一个构造方法后,默认的无参构造方法即失效。

一个类可以有多个构造方法。

//Car.java

public class Car {

    String name;
    String color;
    float price;

    /*
       类中默认的无参构造方法,默认是有的,
       如果没有显示的写出来,如果定义了有参的构造方法,那么无参的就会被覆盖
       以后一般情况下,定义了有参的构造方法,最好把无参显示定义出来
    */
    public Car(){
        //在无参构造方法中,可以使用默认值为对象中的属性赋值
        //引用类型:null  整数:0   浮点:0.0  char:‘ ’  boolean:false
    }

    public void run(){
        System.out.println(this.name+"汽车行驶");
    }

    public void stop(){
        System.out.println(name+"汽车停止");
    }

}
//TestCar.java
public class TestCar {
    public static void main(String[] args) {
        /*
            new Car()  ---> 构造方法
            特点:构造方法名与类名相同,且没有返回值,且不需要void修饰
            作用:在构造方法中为创建的对象初始化赋值
            每次创建对象时,至少要调用一个构造方法,一个类中可以有多个构造方法
        */
        Car bm = new Car();
        bm.name = "宝马";
        bm.color = "黑色";
        bm.price = 200000;
        bm.run();
    }
}

方法的重载

在一个类中有多个方法名称相同的现象。

构造方法,成员方法都可以重载。

如何区分方法:

  • 通过方法参数个数区分
  • 通过类型区分
  • 通过顺序区分

调用时,会根据不同的参数表选择对应的方法。

注意:方法重载跟方法的返回值类型没有任何关系。

重载的作用:扩展方法功能。

//构造方法
public Car(){
    //在无参构造方法中,可以使用默认值为对象中的属性赋值
    //引用类型:null  整数:0   浮点:0.0  char:‘ ’  boolean:false
}

public Car(String name,String color,float price){
    //this表示当前正在被使用的对象
    this.name = name;  //此name是成员变量中的name
    this.color = color;
    this.price = price;
}
//构造方法
public Car(String name,String color){
    this.name = name;  //此name是成员变量中的name
    this.color = color;
}

public Car(float price,String name,String color){
    //this表示当前正在被使用的对象
    this.name = name;  //此name是成员变量中的name
    this.color = color;
    this.price = price;
}
//成员方法
public void run(){
    System.out.println(this.name+"汽车行驶");
}

public void run(int speed){
    System.out.println(this.name+"汽车以"+speed+"速度行驶");
}
public class TestCar {
    public static void main(String[] args) {
        Car bm = new Car();
        bm.name = "宝马";
        bm.color = "黑色";
        bm.price = 200000;
        bm.run();

        Car bc = new Car("奔驰","红色",300000);
        bc.run();

        Car dz = new Car("大众","红色");
        dz.run(120);
    }
}

对象与引用

java中除了8种基本类型外,其余的都是引用类型。

基本类型:使用关键字声明,结构简单。

int a = 10;

引用类型:类、数组、结构……

​ 类是符合类型,比较复杂可以定义更多的东西

Car dz = new Car("大众","红色");

Car ad = dz; //创建了2个对象  ad、dz指向相同的对象
ad.name = "奥迪";
System.out.println(ad.name);  //奥迪
System.out.println(dz.name);  //奥迪
System.out.println(bc.name);  //奔驰

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Desjw9nZ-1642687013933)(E:\Java学习\2022-1-17java第三章面向对象2\课件\对象创建内存图.png)]

值传递与引用传递

严格来讲,参数传递只有值传递

为了基本类型和引用类型区分:分为值传递和引用传递

  • 值传递特指基本类型。

    方法调用时,实际参数把它的值传递给 对应的形式参数,形式参数只是用实际参数的值初始化自己的存储单元内容,是两个不同的存储单元,所以方法执行中形式参数值的改变不影响实际参数的值。

    public class TestValue {
        public static void main(String[] args) {
            int a = 10;
            TestValue t = new TestValue();
            t.test(a);
            System.out.println("a:"+a);  //a的值是多少? 10
        }
    
        /*
            基本类型就是值传递
        */
        public void test(int b){
            System.out.println("b:"+b);  //10 
            b = 20;
        }
    }
    
  • 引用传递对应的是引用类型。

    也称为传地址。方法调用时,实际参数是对象,这时实际参数与形式参数指向同一个地址,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,这个结果在方法结束后被保留了下来,所以方法执行中形式参数的改变将会影响实际参数。

    public class TestValue {
        public static void main(String[] args) {
            TestValue t = new TestValue();
            Car car1 = new Car();
            car1.name = "奔驰";
            t.test(car1);
            System.out.println("car1.name:"+car1.name);  //大众
        }
    
        /*
            引用类型  传递的不是对象本身,而是传递对象的引用地址
        */
        public void test(Car car2){
            System.out.println("car2.name:"+car2.name);  //奔驰
            car2.name = "大众";
        }
    }
    
    

基本类型传递的是该数据值本身。引用类型传递的是对对象的引用,而不是对象本身 。

this关键字

this关键字代表当前正在使用的对象。

static关键字

static被称为静态,可以用来修饰类的属性,方法,代码块,内部类。

  • 随着类的加载而加载
  • 优先于对象存在
  • 修饰的成员,被所有对象共享
  • 可不创建对象,直接被类调用。

静态属性是类的所有对象共享的,即不管创建了多少个对象,静态属性在内存中只有一个。

public class Aodi {
    /*
       Aodi 他们的名字应该都叫奥迪,在定义类的时候直接对其进行赋值。
            型号和价格是不一样的
    */
    String model;
    float price;
    //static修饰的成员变量在内存中只有一份,所有对象可以共享,随着类的加载而加载,通过类名调用
    static String name = "奥迪";
}

public class TestAodi {
    public static void main(String[] args) {
        
        System.out.println(Aodi.name); //可以不创建对象,直接被类调用

        Aodi a8 = new Aodi();
        a8.model = "a8";
        a8.price = 300000;
        System.out.println(Aodi.name+":"+a8.model+":"+a8.price); //可通过类名直接调用

        Aodi q8 = new Aodi();
        q8.model = "q8";
        q8.price = 500000;
        System.out.println(q8.name+":"+q8.model+":"+q8.price);
    }
}

static方法可以使用对象调用,也可以直接用类名调用,建议用类名直接调用 。

在static方法内部只能访问类的static属性,不能访问类的非static属性,static属性先加载。

静态的成员随着类加载后,就可以使用了。而非静态的必须要创建对象后,才可以使用。

//static 修饰的方法是静态方法,属于类,只能使用静态的成员变量。
public static void run(){
    System.out.println(name);
    System.out.println(this.model); //报错  非静态创建对象后才能使用
}

//可以直接使用
Aodi.run();

代码块

代码块在类中声明,类似于没有名称的方法体。

类加载时就自动执行。

分为实例代码块,静态代码块。

  • 实例代码块:在创建对象时调用。
  • 静态代码块:在类加载时调用,只调用一次(因为类只加载一次)。
{
    System.out.println("实例代码块1");
}
{
    System.out.println("实例代码块2");
}
/*
   以后,把在类加载时,就需要自动执行的内容,写在静态代码块中,只执行一次
*/
static {
    System.out.println("静态代码块1");
}
static {
    System.out.println("静态代码块2");
}

public class Test {
    public static void main(String[] args) {
        new Aodi();  //第一次创建对象,并加载类
        new Aodi();  //第二次创建对象,不加载类
    }
}

//静态代码块有限执行,且执行一次。
//原因:类比对象优先加载,且只加载一次
/*输出结果为:
静态代码块1
静态代码块2
实例代码块1
实例代码块2
实例代码块1
实例代码块2
*/

包:为了更好的管理java中的类,创建包来进行管理,用于区别类名的命名空间。

包在硬盘上来讲其实就是文件夹,但在java项目中和文件是有区别的,是作为类的路径存在的。

directory:文件夹 package:包

同一个包下,不会有两个相同的类名。

包的作用:

  • 避免类重名 (区别重名类)

    package Day3;
    
    //import  使用其他包中的类时,需要导入其他包中的类(同一个包的类、java.lang包不用导入)
    import Day2.Car;
    
    public class Test {
        public static void main(String[] args) {
            String s;  //java.lang包
            /*
               Car是类的简称  类的全称(全类名)Day2.Car
            */
            new Car();  //Day2包里的Car
            new Day1.Car();  //Day2中的Car已导入,只能使用全类名
    
    
        }
    }
    
    
  • 按照不同功能管理类

    eg. 控制层、数据访问层、业务逻辑处理层、公共类、配置类、工具类等

  • 控制访问权限

    访问权限修饰符(见下个标题)

包的命名规范:在包名中,可以使用 . 号来区分包的级别,包名一般情况下是小写 。

  • 第一级 指该项目的类型,如com(商业公司),org(组织),gov(政府),edu(教育)等,
  • 第二级 指项目所开发或者运行的公司名称,如:oracle,sun,huawei 等
  • 第三级 指项目的名称,如:bcms,oa,erp,cms等
  • 第四级 指项目模块的名称,如:bean,action,exception等

访问权限修饰符

按照不同功能管理类

控制访问权限

Java语言有四个权限访问修饰符,权限从大到小依次为:

  • public :公共权限 修饰类、属性、方法。可以被任意类访问
  • protected:受保护的权限 修饰属性、方法。 可以被同包类访问,如果不是同包类,必须是该类的子类才可以访问。
  • default:同包权限 修饰类、属性、方法。只能被同包的类访问
  • private:私有权限 修饰属性、方法。 只能在本类中访问

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ubA98y4u-1642687013940)(E:\Java学习\访问权限修饰符.png)]

package com.ffyc.javaoop.day3;
    /*
       类  只能用public 和 默认 修饰
    */
public class Demo {
    /*
       public 公共权限       在任何类中都可以访问到
       protected 受保护权限  在自己类中,同包的其他类中,不同包的子类中可以访问到
                 默认权限    在自己类中,同包的其他类中
       private   私有权限    只能在自己类中访问到
    */

    public String pubName;
    protected String proName;
    String delname;  //默认
    private  String priName;

    protected  void test1(){

    }
    protected void test2(){


    }
    void test3(){

    }
    private void test4(){
        
    }
    
    public void test(){
        Demo d = new Demo();
        d.pubName = "p";
        d.proName = "po";
        d.delname = "";
        d.priName = "pi";
    }
}
package com.ffyc.javaoop.day3.child;

import com.ffyc.javaoop.day3.Demo;

public class ChildDemo extends Demo{
    public void test(){
        Demo d = new Demo();
        d.pubName = "a";  //只剩下公共的

        ChildDemo cd = new ChildDemo();  //默认权限和私有权限仍访问不到
        cd.proName = "1";
        cd.pubName = "q";
    }
}
package com.ffyc.javaoop.day3;

public class Demo1 {
    public void test(){
        Demo d = new Demo();
        d.pubName = "a";
        d.proName = "p";
        d.delname = "d";
    }
}

面向对象的三大特征

面向对象语言的三大特征:

  • 封装
  • 继承
  • 多态

封装

封装:将某个功能封装成一个方法。eg. 写了一个工具类,定义好了几个常用的方法。

面向对象中的封装:是隐藏(访问权限修饰符 private、protected、默认、public……)将类中的某些信息不对外开放。

private String name;  //属性私有化,只是封装的一种表示

封装特点:

  • 隐藏类的实现细节
  • 方便加入控制语句
  • 只能通过规定方法访问
  • 方便修改实现
package com.ffyc.javaoop.day3.pack;

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

    public void setAge(int age){
        if(age>18){
            this.age = age;  //this.age对象中的age
        }
    }

    public int getAge(){
        return age;
    }

    //setXXX方法就是为私有属性提供访问的公共方法
    public void setName(String name){
        //方便加入控制语句
        if(name.length()>3 && name.length()<6){
            this.name = name;
        }
    }

    public  String getName() {
        return this.name;
    }

}
package com.ffyc.javaoop.day3.pack;

public class TestPerson {
    public static void main(String[] args) {
        //private 将name属性隐藏,在其他类中无法访问
        Person zs = new Person();
//        zs.name = "fadsf";
        zs.setName("fsdfj");
        System.out.println(zs.getName());
    }
}

单例模式:(模式就是模板,解决一种问题,就有)

​ 单例模式解决在一个程序中,只能让一个类创建一个对象。

package com.ffyc.javaoop.day3.pack;

public class WindowDemo {
    static WindowDemo windowDemo = null;

    /*
       将构造方法私有化,这样在其他类中就不能创建对象了
    */
    private WindowDemo(){

    }

    //向外提供一个方法,用来创建唯一的一个对象,并返回此对象
    public static WindowDemo getWindowDemo(){
        //单例模式
        //第一次已经创建,第二次windowDemo不为null,因而直接返回windowDemo
        if(windowDemo == null){
            windowDemo = new WindowDemo();
        }
        return windowDemo;
    }
}
package com.ffyc.javaoop.day3.pack;

public class TestWindow {
    public static void main(String[] args) {
//        new WindowDemo(); 构造方法私有,无法创建对象
        System.out.println(WindowDemo.getWindowDemo());
        System.out.println(WindowDemo.getWindowDemo());
    }
}

继承

继承:是面向对象程序设计不可缺少的设计思想,实现代码可重用,提高代码可扩展性的主要途径。

什么时候使用继承:

  • 可以把一些共有属性行为抽取出来,创建一个父类,让其他类继承即可。

    eg. 猫是动物 狗是动物 是属于同一类 大小的关系

基本语法:

  • 父类 —> 子类
  • 子类 extends 父类 extends Object
public class Animal extends Object{
    private String name;
    private int age;

    public void eat(){
        System.out.println(this.name+"动物吃东西");
    }

    //get set方法 专属用于私有属性赋值
    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;
    }
}


/*
   子类继承父类  使用extends关键字
   一个类只能直接继承一个父类,但是可以间接继承
*/
public class Dog extends Animal{

}


public class AngelDog extends Dog{
    //扩展字节的功能,同时重复调用父类的功能
    public void fly(){
        System.out.println("哮天犬会飞");
    }
}
public class Test1 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.setName("可可");
        dog.setAge(5);
        System.out.println(dog.getName());
        System.out.println(dog.getAge());
        dog.eat();
    }
}

继承是从已有的类中派生出新的类,新的类能吸收已有类的属性和行为,并能扩展新的能力。

  • 在JAVA中使用extends关键字来表示继承关系。
  • JAVA不支持多继承,单继承使JAVA的继承关系很简单,一个类只能有一个直接父类。
  • 继承之后子类可以调用父类的所有非私有属性和非私有方法

符合is-a关系的设计,使用继承。将子类共有的属性和行为放到父类中。

继承的传递性:

  • C类从B类继承,B类又从A类继承,那么C类就具有B类和A类的所有非私有属性和非私有方法。
  • 当一个没有显示的继承任何一个类时,那么jvm会默认让类继承Object类,Object(java.lang包)是所有类的基类(父类/超类)。

继承中的构造方法:

  • 在创建对象,调用构造方法时,子类的构造方法会默认去调用父类的构造方法。因为要先初始化父类,子类才可以去使用父类中的属性行为。

    构造方法可以用来初始化

  • 使用super关键字调用父类任意一个构造方法,必须写在构造方法的第一行。

  • 如果子类的构造方法中没有显式地调用基类构造方法,则系统默认调用基类无参数的构造方法。

    public class AngelDog extends Dog{
        //扩展字节的功能,同时重复调用父类的功能
        public void fly(){
            System.out.println("哮天犬会飞");
        }
    
        public AngelDog(){ //super表示父类,并不是父类对象
            //super()调用父类构造方法,默认存在,可以不写,在子类构造方法的第一行
            //如果显示的调用,必须在第一行调用
            super(); 
            System.out.println("AngelDog类无参构造");
        }
    }
    

super关键字用途:

  • 使用super关键字访问父类成员。

  • 用super.成员变量名来引用父类成员变量。

  • 用super.方法名(参数列表)访问父类的方法。

  • 用super.构造方法(参数列表)访问父类构造方法。

  • 注:不要把super误认为是父类对象.在创建子类对象时, 不会创建父类对象,只会将父类中的信息加载到子类对象中存储。

    public AngelDog(){  //super表示父类
        super();
        System.out.println("AngelDog类无参构造");
        super.eat();
    }
    

方法的重写:当父类的方法实现不能满足子类需求时,可以对方法进行重写(override)。

  • 重写要求:与类中的方法名一致,参数、返回值一致,访问权限等于或大于父类权限。

  • @Override 是java中的注解标签 用来标记的。作用在方法上,用来表示此方法是从父类中重写而来的,在编译期间检测语法格式。

    /*
    神犬吃东西实现方式与其他动物不一样,那么就可以在哮天犬类中重写(覆盖)Animal类中的eat()方法  方法重写
    重写的要求:与父类中的方法名一致,参数、返回值一致  访问权限等于或大于父类权限
    
    @Override 是java中的注解标签,用来标记的
    @Override 作用在方法上,表示此方法是从父类中重写而来的,在编译期间检测语法格式。
    */
    @Override
    public void eat(){
        System.out.println("哮天犬坐着吃饭");
    }
    

多态

同一种事物,在不同时刻表现不同的状态 。

前提:要有继承(包括接口实现),要有方法重写,父类的引用指向子类对象。

//父类的引用指向子类对象
Animal dog1 = new Dog();
Animal cat1 = new Cat();
Object d = new Dog();

Dog dog = new Dog();  //Dog的引用指向Dog对象
Cat cat = new Cat();  

编译期间:写代码时就是编译期间,Animal dog1 在编译期间是Animal类型。

运行期间:run运行程序。Animal dog1 在运行期间是Dog类型。

对于成员方法来讲,编译看左边,运行看右边。

对象在运行时才创建。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JD3FJj9a-1642687013942)(E:\Java学习\2022-1-19java第三章面向对象4\课件\Snipaste_2022-01-19_11-26-24.png)]

对于静态方法来讲,编译和运行都看左边。

对于成员变量来讲,编译和运行都看左边。

多态:提高了程序的扩展性,因而子类类型向上转为父类类型。

多态存在不足:使用多态时,不能访问子类中特有的方法,因为已经向上转为父类类型,编译期间不能调用子类特有方法。

解决:需要向下转型,转型前最好判断类型,使用instanceof关键字来判断。

public class Test2 {
    public static void main(String[] args) {
        /*
           创建一个喂不同动物,动物吃东西的功能。
           不用多态来实现,扩展性不好。
        */
        Dog dog = new Dog();
        Cat cat = new Cat();

        Test2 t = new Test2();
        t.feedDog(dog);
        t.feedCat(cat);
    }

    public void feedDog(Dog dog){
        dog.eat();
    }

    public void feedCat(Cat cat){
        cat.eat();

    }
}
public class Test3 {
    public static void main(String[] args) {
        /*
           创建一个喂不同动物,动物吃东西的功能。
           用多态来实现。
           把子类类型上升为父类类型,可以用父类类型表示所有的子类对象  (多态的好处)
        */
        Animal dog = new Dog();
        Animal cat = new Cat();

        Test3 t = new Test3();
        t.feedAnimal(dog);
        t.feedAnimal(cat);
    }

    public void feedAnimal(Animal animal){
        animal.eat();
//        animal.play();  animal中无play()方法因而报错,需要向下转型
//        Dog dog = (Dog) animal;
//        dog.play();  //Cat类中无play()因而cat报错
        //向下类型转换时,需要做一个判断
        //关键:instanceof  检测animal在运行时,实际的类型是否为Dog,如果是返回true,否则返回false。
        if(animal instanceof Dog){
            Dog dog = (Dog)animal;
            dog.play();
        }
    }
}

抽象类

抽象就是一个概念,不是具体的。

抽象方法:

  • 抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。
  • 抽象方法必须用abstract关键字进行修饰。
  • 在一些体系结构比较庞大的体系中,可以将顶层的类中的方法定义为抽象的。

抽象类:

  • 如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

  • 抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法。

  • 用abstract修饰的类就是抽象类。如果某个类中包含有抽象方法,那么该类就必须定义成抽象类

    /*
       如果一个类中有抽象的方法,name这个类必定是抽象类
       但是抽象类中不一定有抽象方法
       抽象类就是一个不完整的类,里面有抽象方法
       抽象类因为没有具体实现的抽象方法,所以抽象类不能创建对象,除了不能创建对象外,其他功能和正常类一致。
    */
    public abstract class Animal {
        private  String name;
        int age;
    
        /*
           abstravt 修饰的方法是抽象方法,可以没有具体的实现
           只是作为一个功能的定义,在顶层类中往往只需要定义功能即可,让其他类去实现
        */
        public abstract void eat();
    
        public Animal(){
    
        }
    
        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 class Dog extends Animal{
        private String type;
    
        public String getType() {
            return type;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    }
    
    /*
       哮天犬就是一个具体的类,重写父类中的抽象方法
    */
    public class AngelDog extends Animal{
        @Override
        public void eat(){
            System.out.println("哮天犬坐着用餐");
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            AngelDog xtq = new AngelDog();
            xtq.setAge(1000); //非抽闲的依旧可以调用
            xtq.eat();
        }
    }
    

抽象类特点:

  • 抽象类不能被实例化,但可以有构造方法。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。
  • 抽象类只能用作基类,表示的是一种继承关系。继承抽象类的非抽象类必须实现其中的所有抽象方法,而已实现方法的参数、返回值要和抽象类中的方法一样。否则,该类也必须声明为抽象类。

final关键字

final用于声明属性、方法和类。

  • 属性:final修饰的属性是常量,值不可以改变,必须要初始化赋值。

    //在定义时,直接为其赋值,值不可以改变。建议使用static赋值,在整个内存中值只有一份。
    static final int num = 100;
    //在定义时,没有为常量赋值,必须在构造方法中赋值。在每一个对象中,都可以拥有一个常量。
    final int count;
    //创建一个有参的构造方法
    public finalDemo(int count) {
        this.count = count;
    }
    
    public void test(){
    //        num = 10;  //final修饰无法赋值
        new String("abc");
        //只有创建对象时,在其构造方法中为其赋值。
        new finalDemo(10);
        new finalDemo(20);
    }
    
  • 方法:final修饰的方法不能被子类重写,不能修饰抽象的方法。

    public final void test(){
        //final修饰的方法不能被子类重写
    }
    
  • 类:修饰后的类不能被继承,final不能修饰抽象类、接口。

接口

接口(USB接口):专注于功能的设计,而不是实现。让其他类去具体实现即可。与抽象类类似,但有区别。

基本语法:

  • 接口中所有属性默认为:public static final 静态常量
  • 抽象方法默认:public abstract 修饰
  • jdk8以后添加了静态方法,接口可以直接调用。
  • jdk8以后添加了默认方法,通过子类调用。
public interface Myinterface {

//    public static final int NUM = 10; //必须赋值  NUM常量   前面默认有public static final
    int NUM = 10;  //接口种定义的属性默认是静态常量

//    public abstract void eat();  前面默认是public abstract修饰
    void eat();
    void sleep();

    //java8之后,新增加两种方法(静态方法,默认方法)
    //静态方法 接口自己调用
    public static void test1(){
        System.out.println("test1 "+NUM);
    }
    //默认方法 是让子类重写,或者让子类调用
    public default void test2(){
        System.out.println("test2");
    }
}

public class Test {
    public static void main(String[] args) {
        System.out.println(Myinterface.NUM);
        Myinterface.test1(); //静态方法
//        Myinterface.test2();  默认方法无法直接调用
    }
}

接口的继承:

  • 一个类只能直接继承一个类
  • 一个类可以实现多个接口
  • 一个接口可以继承多个接口
public class MyinterfaceImpl extends Object implements Myinterface,InterfaceC{
    //MyinterfaceImpl :Myinterface类的名字,Impl接口的实现

    //静态方法不能重写,默认方法可重写可不重写
    /*
       一个类实现接口,要么将此类继续声明为抽象类;要么重写接口中的所有抽象方法。
    */
    @Override
    public void eat() {

    }

    @Override
    public void sleep() {

    }
    //默认方法可重写可不重写
    @Override
    public void test2() {

    }
}

public interface Myinterface extends InterfaceA,InterfaceB{}

接口的特性:

  • 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字
  • 接口中方法可以是抽象的,静态的,默认的
  • 接口中声明的属性默认为 public static final 的
  • 接口不是被类继承了,而是要被类实现
  • 接口不能实例化对象,无构造方法
  • 一个类可以实现多个接口
  • 与继承关系类似,接口与实现类之间存在多态性
  • 一个接口能继承其它多个接口
  • 当类实现接口的时候,类要实现接口中所有的抽象方法。否则,类必须声明为抽象的类

抽象类和接口的区别

相同点:

  • 都不能创建对象
  • 都可以表示多态性

不同点:

  • 接口
    • 接口不能有构造方法
    • 不能有成员变量
    • 不能有成员方法,只有静态方法、默认方法
  • 抽象类
    • 能有构造方法
    • 能有成员变量

什么时候使用接口,什么时候使用抽象类:

public abstract class Animal {
    private String name;

    public Animal(){

    }

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

    public abstract void eat();

    public abstract void sleep();

    public String getName() {
        return name;
    }

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

public class Bird extends Animal implements CanFly,CanCry{
    @Override
    public void eat() {

    }

    @Override
    public void sleep() {

    }

    @Override
    public void cry() {

    }

    @Override
    public void fly() {

    }
}

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

    }

    @Override
    public void sleep() {

    }
}

public interface CanCry {
    void cry();
}

public interface CanFly {
    void fly();
}

public class Test {
    public static void main(String[] args) {
        Animal bird = new Bird();
        CanFly b = new Bird();  //接口也可以作为父类类型来存在
        CanCry c = new Bird();
//        CanCry d = new Dog();  Dog没有CanCry的接口,无法实现
    }
}
这篇关于03Java面向对象的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!