Java基础之面向对象

1.面向对象

面向对象的三大特性:封装性、继承性、多态性

封装

1.方法就是一种封装

2.关键字private也是一种封装

封装就是将一些细节信息隐藏起来,对于外界不可见

package com.dcits.day05.demo03;
​
public class Demo02Method {
    public static void main(String[] args) {
        int[] array = {5,15,25,35,111};
        int max = getMax(array);
        System.out.println(max);
​
    }
    public static int getMax(int[] array) {
        int max = array[0];
        for (int i = 0; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        return max;
    }
}

 

private关键字的作用以及使用

一旦使用了private进行修饰,那么本类中可以随意访问,但是超出了本类的范围就不能再访问了

可以通过间接访问的方式,自定义一对儿Getter/Setter方法,必须叫 setXxx 或者是 getXxx

对于Getter来说,不能有参数,返回值类型和成员变量对应

对于Setter来说,不能有返回值,参数类型和成员变量对应

// Person类
package com.dcits.day05.demo03;
​
public class Person {
    String name;
    private int age;
    public void show() {
        System.out.println("我叫:" + name  +",今年" + age);
    }
    public void setAge(int num) {
        if (num < 100 && num >=9) {
            age = num;
        } else {
            age = 0;
            System.out.println("数据不合理");
        }
    }
    public int getAge() {
        return age;
    }
}
​
// 调用
package com.dcits.day05.demo03;
​
public class Demo03Person {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "赵丽颖";
//        person.age = 18; 当成员变量被private修饰的时候,外部无法访问,只能通过间接的方式Setter,Getter
        person.setAge(-20);
        person.show();
    }
​
}
 

布尔类型的特殊情况

//
package com.dcits.day05.demo03;
​
public class Student {
    private String name;
    private int age;
    private boolean male;
​
    public void setMale(boolean b){
        male = b;
    }
    public boolean isMale() {
        return male;
    }
​
    public void setName(String str){
        name = str;
    }
    public String getName() {
        return name;
    }
    public void setAge(int num) {
        age  = num;
    }
    public int getAge() {
        return age;
    }
}
// 调用
package com.dcits.day05.demo03;
​
public class Demo04Student {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.setName("alex");
        stu.setAge(10);
        stu.setMale(true);
​
        System.out.println(stu.getName());
        System.out.println(stu.getAge());
        System.out.println(stu.isMale());
    }
}
​

 

this关键字的使用

当方法的局部变量和类的成员变量重名的时候,根据就近原则,优先使用局部变量,如果需要访问 本类当中的成员变量,需要使用格式:this.成员变量

通过谁调用的方法,谁就是this

//
package com.dcits.day05.demo04;
​
public class Person {
    String name;
    public void sayHi(String name) {
        System.out.println(this.name + "你好,我是" + name);
    }
}
// 调用
package com.dcits.day05.demo04;
​
public class Demo01Person {
    public static void main(String[] args) {
        Person person = new Person();
        person.name = "6666";
        person.sayHi("777");
    }
}

构造方法

构造方法是专门用来创建对象的方法,当我们使用关键字new来创建对象的时候,其实就是在调用构造方法

注意事项:

  • 构造方法的名称必须和所在的类名称完全一样,就连大小写也要完全一样

  • 构造方法不要写返回值类型,连void都不要写

  • 构造方法不能return一个具体的返回值

  • 如果没有编写任何构造方法,那么编译器默认会赠送一个构造方法,没有参数、方法体什么都不做

  • 一旦编写了一个构造方法,那么编译器就不再赠送

  • 构造 方法也是可以重载的

//
package com.dcits.day05.demo04;
​
public class Student {
    private String name;
    private int age;
    public Student(String name,int age) {
        this.name = name;
        this.age = age;
        System.out.println("有参数的构造方法!!");
    }
    public Student() {
        System.out.println("无参数的构造方法执行啦!!");
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setAge(int age) {
        this.age = age;
​
    }
    public int getAge() {
        return age;
    }
}
// 调用
package com.dcits.day05.demo04;
​
public class Demo02Student {
    public static void main(String[] args) {
        Student stu = new Student();
        Student stu1 = new Student("aaa",20);
        stu1.setAge(23);
        System.out.println(stu1.getAge());
        System.out.println(stu1.getName());
​
    }
​
}
​

 

局部变量和成员变量

  1. 定义的位置不一样

    • 局部变量:在方法的内部

    • 成员变量:在方法的外部,直接写在类当中

  2. 作用范围不一样

    • 局部变量:只有方法 才可以使用,出了方法就不能再使用了

    • 成员变量:整个类都可以通用

  3. 默认值不一样

    • 局部变量:没有默认值,如果想要用,必须手动赋值

    • 成员变量:如果没有赋值,会有默认值,规则和数组一样

  4. 内存的位置不一样

    • 局部变量:位于栈内存

    • 成员变量:位于堆内存

  5. 生命周期不一样

    • 局部变量:随着方法进栈而诞生,随着方法出栈而消失

    • 成员变量:随着对象创建而诞生,随着对象被垃圾回收而消失

标准类的组成部分

一个标准的类通常拥有下面的四个部分:

  1. 所有的成员变量都要使用private关键字来修饰

  2. 为每一个成员变量编写一对Getter、Setter方法

  3. 编写一个无参数的构造方法

  4. 编写一个全参数的构造方法

继承

继承是多态的前提,如果没有集成,就没有多态

继承解决的主要问题就是:共性抽取

定义类时的两个注意事项:

  • 成员变量时直接定义在类当中的,在方法外面

  • 成员方法不要写static关键字

继承的格式:

// 父类
package com.dcits.day08.demo01;
​
public class Employee {
    public void method() {
        System.out.println("父类执行!");
    }
}
// Teacher子类
package com.dcits.day08.demo01
​
public class Teacher extends Employee{
​
}
// Assistant子类
package com.dcits.day08.demo01;
​
public class Assistant extends Employee {
}
// 调用
package com.dcits.day08.demo01;
​
public class Demo01Extends {
    public static void main(String[] args) {
        Teacher teacher = new Teacher();
        Assistant assistant = new Assistant();
        teacher.method();
        assistant.method();
    }
}
 

在父子类的继承关系当中,如果成员变量重名,则创建子类时,访问有两种方式:

  • 直接通过子类对象访问成员变量

    • 等号左边是谁,就优先使用谁,没有则向上找

  • 间接通过成员方法访问成员变量

    • 该方法属于谁,就优先用谁,没有则向上找

// 父类
package com.dcits.day08.demo02;
​
public class Fu {
    int numFu = 10;
    int num = 100;
    public void methodFu() {
        System.out.println(num);
    }
}
​
// 子类
package com.dcits.day08.demo02;
​
public class Zi extends Fu {
    int numZi = 20;
    int num = 200;
    public void methodZi() {
        System.out.println(num);
    }
}
​
// 调用
package com.dcits.day08.demo02;
​
public class Demo01ExtendsField {
    public static void main(String[] args) {
        Fu fu = new Fu();
        System.out.println(fu.numFu);
​
        Zi zi =  new Zi();
        System.out.println(zi.numFu);
        System.out.println(zi.numZi);
​
        // 当父类与子类的成员变量重名的时候
        System.out.println(zi.num);
//        System.out.println(zi.abc);
        //
        zi.methodZi();
        zi.methodFu();
    }
​
​
}

 

 

区分子类方法中的三种重名变量

  • 直接使用的方法中的变量

  • this.变量名:调用本类中的成员变量

  • super.变量名:调用父类中的成员变量

// 父类
package com.dcits.day08.demo03;
​
public class Fu {
    int num = 10;
}
// 子类
package com.dcits.day08.demo03;
​
public class Zi extends Fu {
    int num = 20;
    public void method() {
        int num = 30;
        System.out.println(num); // 30 局部变量
        System.out.println(this.num); // 20 本类的成员变量
        System.out.println(super.num); // 10 父类的成员变量
    }
}
// 调用
package com.dcits.day08.demo03;
​
public class Demo01ExtendsField {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method();
    }
}
​

 

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

在父子类的继承关系当中,创建子类对象,访问成员方法的规则:创建的对象是谁,就优先使用谁,如果没有则向上找

注意:无论是成员方法还是成员变量,如果没有都是向上找父类u,绝不会向下找子类

// 父类
package com.dcits.day08.demo04;
​
public class Fu {
​
    public void methodFu() {
        System.out.println("父类中的方法执行啦!");
    }
​
    public void method() {
        System.out.println("父类重名执行啦!");
    }
}
​
// 子类
package com.dcits.day08.demo04;
​
public class Zi extends Fu {
    public void methodZi() {
        System.out.println("子类中的方法执行啦!");
    }
    public void method() {
        System.out.println("子类重名执行啦!");
    }
}
​
// 调用
package com.dcits.day08.demo04;
​
public class Zi extends Fu {
    public void methodZi() {
        System.out.println("子类中的方法执行啦!");
    }
    public void method() {
        System.out.println("子类重名执行啦!");
    }
}
 

继承方法中的覆盖重写

重写:方法的名称一样,参数列表也一样,覆盖、覆写

重载:方法的名称一样,参数列表不一样

方法的覆盖重写特点:创建的是子类对象,则优先用子类方法

方法覆盖重写的注意事项:

  1. 必须保证父子类之间的方法名称相同、参数列表也相同

  2. @Override:写在方法前面,用来检测是不是有效的正确覆盖重写,这个注释就算不写,只要满足要求,也是正确的覆盖重写

  3. 子类方法的返回值必须小于等于父类方法的返回值范围。Object类是所有类的父类

  4. 子类方法的权限必须大于等于父类方法的权限修饰符。public > protected > (default) > private 注意:(default)不是关键字default,而是什么都不写,留空

继承中方法的覆盖重写应用场景

// 父类
package com.dcits.day08.demo06;
// 本来的老款手机
public class Phone {
    public void   call() {
        System.out.println("打电话");
    }
​
    public void send() {
        System.out.println("发短信");
    }
​
    public void show() {
        System.out.println("显示号码");
    }
}
​
// 子类
package com.dcits.day08.demo06;
// 上市的新款手机
public class NewPhone extends Phone {
    @Override
    public void show() {
//        System.out.println("显示号码");
        super.show();
        System.out.println("显示姓名");
        System.out.println("显示头像");
    }
}
​
// 调用
package com.dcits.day08.demo06;
​
public class Demo01Phone {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.call();
        phone.send();
        phone.show();
        System.out.println("===========");
​
        NewPhone newPhone = new NewPhone();
​
        newPhone.call();
        newPhone.send();
        newPhone.show();
    }
}

 

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

  1. 子类构造方法当中有一个默认隐含的 "super()" 调用,所以一定是先调用的父类构造,后执行的子类构造

  2. 子类构造可以通过super关键字来调用父类重载构造

  3. super的父类构造调用,只能是第一个语句 ,不能一个子类构造调用多次super构造

  4. 子类必须调用父类构造方法,不写赠送super() 写了则用写的指定该的super调用,super只能有一个,还必须是第一个

super关键字的用法(访问父类的内容):

  1. 在子类的成员方法中,访问父类的成员变量

  2. 在子类的成员方法中,访问父类的成员方法

  3. 在子类的构造方法中,访问父类的构造方法

// 父类
package com.dcits.day08.demo08;
​
public class Fu {
    int num = 10;
    public void method(){
        System.out.println("父类方法");
    }
}
​
// 子类
package com.dcits.day08.demo08;
​
public class Zi extends Fu {
    int num = 20;
    public Zi(){
        super();
    }
    public void methodZi() {
        System.out.println(super.num); // 父类的num
    }
    public void method(){
        super.method();
        System.out.println("子类方法");
    }
}
​

 

this关键字的三种使用方法(访问本类的内容)

  1. 在本类的成员方法中,访问本类的成员变量

  2. 在本类的成员方法中访问本类的另一个成员方法

  3. 在本类的构造方法中,访问本类的另一个构造方法

注意:

  • 在第三种用法中要注意:this(..)调用必须是构造方法的一个语句,唯一一个

  • super和this两种构造调用,不能同时使用

// 父类
package com.dcits.day08.demo09;
​
public class Fu {
    int num = 30;
}
// 子类
package com.dcits.day08.demo09;
​
public class Zi extends Fu {
    int num = 20;
    public Zi(){
        this(123); // 本类的无参构造,调用本类的有参构造
//        this(1,2)
    }
    public Zi(int n){
​
    }
    public Zi(int n,int m){
​
    }
    public void showNum(){
        int num = 10;
        System.out.println(num);
        System.out.println(this.num); // 本类中的成员变量
        System.out.println(super.num); // 父类中的 成员变量
    }
    public void methodA() {
        System.out.println("AAA");
    }
    public void methodB() {
        methodA();
        this.methodA();
        System.out.println("BBB");
    }
}

this、super的关键字图解

Java语言继承的三个特点:

  • 一个类的 直接父类只能有唯一一个

  • Java语言可以多继承

  • 一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类

 

多态

多态的定义以及基本使用

extends继承或者implements实现,是多态的前提。

小明这个对象既有学生形态,也有人类形态。一个对象拥有多种形态,这就是:对象的多态性

代码当中体现多态性,其实就是一句话:父类引用指向子类对象

格式:

  • 父类名称 对象名 = new 子类名称()

  • 接口名称 对象名 = new 实现类名称()

// 父类
package com.dcits.day09.demo04;
​
public class Fu {
    public void method(){
        System.out.println("父类方法");
    }
    public void methodFu(){
        System.out.println("父类特有方法");
    }
}
// 子类
package com.dcits.day09.demo04;
​
public class Zi extends Fu {
    @Override
    public void method() {
        System.out.println("子类方法");
    }
}
// 调用
package com.dcits.day09.demo04;
​
​
​
public class Demo01Multi {
    public static void main(String[] args) {
        // 使用多态的写法
        // 左侧父类的引用指向右侧子类的对象
        Fu obj = new Zi();
        // new 的是谁就调用谁 的方法
        obj.method(); // 子类方法
        obj.methodFu(); // 父类特有方法
    }
}
​

 

多态中成员变量的使用特点

访问成员变量的两种方式:

  1. 直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有则向上找

  2. 间接通过成员方法访问成员变量,看该方法属于谁,优先用谁,没有则像上找

// 父类
package com.dcits.day09.demo05;
​
public class Fu {
    int num = 10;
​
    public void showNum(){
        System.out.println(num);
    }
}
// 子类
package com.dcits.day09.demo05;
​
public class Zi extends Fu {
    int num = 20;
​
    int age = 16;
​
    @Override
    public void showNum() {
        System.out.println(num);
    }
}
// 调用
package com.dcits.day09.demo05;
​
public class Demo01MultiField {
    public static void main(String[] args) {
       Fu obj = new Zi();
        System.out.println(obj.num); // 父类中的10
        System.out.println("=====================");
        obj.showNum(); // 子类没有覆盖重写,就是父类中的num,一旦子类重写后就是子类中的num
    }
}
​

 

多态中成员方法的使用特点

在多态的代码当中,成员方法的优先访问规则是:看new的是谁,就优先用谁,没有则向上找

注意:编译看左边,运行看右边

对比一下:

  • 成员变量:编译看左边,运行还看左边

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

// 父类
package com.dcits.day09.demo05;
​
public class Fu {
    int num = 10;
​
    public void showNum(){
        System.out.println(num);
    }
​
    public void method(){
        System.out.println("父类方法");
    }
    public void methodFu(){
        System.out.println("父类特有方法");
    }
}
// 子类
package com.dcits.day09.demo05;
​
public class Zi extends Fu {
    int num = 20;
​
    int age = 16;
​
    @Override
    public void showNum() {
        System.out.println(num);
    }
​
    @Override
    public void method() {
        System.out.println("子类方法");
    }
    public void methodZi(){
        System.out.println("子类特有方法");
    }
}
​
// 调用
package com.dcits.day09.demo05;
​
public class Demo01MultiField {
    public static void main(String[] args) {
       Fu obj = new Zi();
       obj.method(); // 父子都有,优先使用子类
       obj.methodFu(); // 子类没有,父类有,向上找到父类
        // 编译看左,左边是Fu,没有methodZi方法,所以编译报错
//        obj.methodZi(); // 错误写法
//        System.out.println(obj.num); // 父类中的10
//        System.out.println("=====================");
//        obj.showNum(); // 子类没有覆盖重写,就是父类中的num,一旦子类重写后就是子类中的num
    }
}
​

 

使用多态的好处

对象的向上转型

对象的向上转型,其实就是多态写法

格式: 父类名称 对象名 = new 子类名称()

含义:右侧创建一个子类对象,把它当作父类来看待使用

注意事项:

  • 向上转型一定是安全的,从小范围转到了大范围

  • 但是有一个弊端:对象一旦向上转型为父类,那么就无法调用子类原本的特有内容

类似于:double num = 100 正确 int----double 自动类型转换

// 父类
package com.dcits.day09.demo06;
​
public abstract class Animal {
    public abstract void eat();
}
// 子类
package com.dcits.day09.demo06;
​
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼。。。");
    }
}
​
// 调用
package com.dcits.day09.demo06;
​
public class Demo01Main {
    public static void main(String[] args) {
        Animal animal = new Cat();
        animal.eat();
    }
​
}

 

对象的向下转型

对象的向下转型,其实是一个还原动作

格式:子类名称 对象名 = (子类名称) 父类对象

含义:将父类对象,还原成为原本的子类对象

注意事项:

  • 必须保证对象本来创建的时候,就是猫,才能向下转型成为猫

  • 如果对象创建的时候本来不是猫,现在非要向下转型成为猫,就会报错

类似于:int num = (int) 10.0 正确 int num = (int) 10.5 错误,发生精度损失

// 父类
package com.dcits.day09.demo06;
​
public abstract class Animal {
    public abstract void eat();
}
// 猫子类
package com.dcits.day09.demo06;
​
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼。。。");
    }
​
    public void catchMouse() {
        System.out.println("猫抓老鼠!!");
    }
}
​
// 狗子类
package com.dcits.day09.demo06;
​
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃shit");
    }
​
    public void watchMouse() {
        System.out.println("狗看家!!");
    }
}
​
// 调用
package com.dcits.day09.demo06;
​
public class Demo01Main {
    public static void main(String[] args) {
​
        Animal animal = new Cat(); // 对象的向上转型
        animal.eat();
​
        // 向下转型
        Cat cat = (Cat) animal;
        cat.catchMouse(); // 猫抓老鼠!!
// 下面是错误的向下转型
        // 本来new的时候是一只猫,现在非要转成狗
        // java.lang.ClassCastException
        Dog dog = (Dog) animal; // 错误写法
​
    }
​
}
​

 

用instanceof 关键字进行类型判断

package com.dcits.day09.demo06;
​
public class Demo01Instanceof {
    public static void main(String[] args) {
        Animal animal = new Cat(); // 本来是一只猫
        animal.eat();
​
        // 如果需要调用子类特有的方法,需要向下转型
        if (animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.watchMouse();
        }
        if (animal instanceof Cat){
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }
        giveMeAPet(new Dog()); // 在你调用这个方法的时候,方法本身不知道传递过来的是哪个类,所以需要进行判断
​
    }
​
    public static void giveMeAPet(Animal animal){
        if (animal instanceof Dog){
            Dog dog = (Dog) animal;
            dog.watchMouse();
        }
        if (animal instanceof Cat){
            Cat cat = (Cat) animal;
            cat.catchMouse();
        }
​
    }
}

 

接口多态的综合案例

// USB接口类:两个抽象方法:打开USB、关闭USB
package com.dcits.day09.demo07;
​
public interface USB {
​
    public abstract void open();
​
    public abstract void close();
}
​
// 电脑类:开机、关机、连接USB接口并对USB设备进行对应操作
package com.dcits.day09.demo07;
​
public class Computer {
    public void powerOn(){
        System.out.println("笔记本电脑开机");
    }
​
    public void powerOff(){
        System.out.println("笔记本电脑关机");
    }
​
    // 使用USB设备的方法,使用接口作为方法的参数
    public void useDevice(USB usb) {
        usb.open();
        // 判断当前类是属于哪个类之后,在获取类中的特有方法
        if (usb instanceof Mouse){
            Mouse mouse = (Mouse) usb;
            mouse.click();
        } else if (usb instanceof KeyBoard){
            KeyBoard keyboard = (KeyBoard) usb;
            keyboard.type();
        }
        usb.close();
    }
}
​
// 鼠标类:重写接口类中的打开、关闭功能,并实现自己的独有功能
package com.dcits.day09.demo07;
​
public class Mouse implements USB {
    @Override
    public void open() {
        System.out.println("打开鼠标");
    }
​
    @Override
    public void close() {
        System.out.println("关闭鼠标");
    }
​
    public void click(){
        System.out.println("点击鼠标!");
    }
}
​
// 键盘类:重写接口类中的打开、关闭功能,并实现自己的独有功能
package com.dcits.day09.demo07;
​
public class KeyBoard implements USB {
    @Override
    public void open() {
        System.out.println("打开键盘");
    }
​
    @Override
    public void close() {
        System.out.println("关闭键盘");
    }
​
    public void type(){
        System.out.println("敲键盘!");
    }
}
posted @ 2020-07-13 18:19  大栗  阅读(182)  评论(0编辑  收藏  举报
ヾ(≧O≦)〃嗷~