Java基础部分学习:05、面向对象中级(访问修饰符、封装、继承、多态)

1、访问修饰符

在这里插入图片描述
使用注意事项:

1、修饰符可以用来修饰类中的属性、成员方法及类。

2、只有默认和public才可以修饰类。

3、成员方法的访问规则和属性完全一样。


2、封装:

1、定义:
就是将抽象出来的数据、方法封装在一起,数据被保护在内部,程序的其它部分只能通过被授权的操作,才能对数据进行操作。

封装就是使用 private 修饰符保护数据,使用set、get方法修改及获取数据。

2、封装的意义:

隐藏实现细节,别人只需要调用即可,不关心是如何实现的。

可以对数据进行验证,将不合理的数据排除,保证数据的安全合理。

     public class EncapSulation {
    public static void main(String[] args) {
        Person person = new Person("lisa",100, 20000.0);
        double res = person.getSalary();
        System.out.println(res);
    }
}

class Person {
    public String name;
    private int age;
    private double salary;
    
    // 封装和构造器:
    // 可以将set方法写在构造器里面,这样就不会担心封装被构造器破坏
    public Person(String name, int age, double salary) {
//        this.name = name;
//        this.age = age;
//        this.salary = salary;
        this.setName(name);
        this.setAge(age);
        this.setSalary(salary);

    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }
// 可以在set方法中使用判断语句来控制数据的合理性
    public void setAge(int age) {
        if (age > 1 && age <= 120) {
            this.age = age;
        } else {
            System.out.println("年龄设置不合理");
            this.age = 30;
        }
    }

    public double getSalary() {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入密码");
        int password = scanner.nextInt();
        if (password == 123) {
            return salary;
        } else {
            System.out.println("密码输入错误");
            return 0;
        }
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public void message() {
        System.out.println(this.name + " " + this.age + " " + this.salary);

    }
}


3、继承:

1、定义:

当多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要使用 extends 来声明继承父类即可。

简而言之:就是将多个类共有的属性方法拿出来,让其它需要使用的类来继承它(使用它)。

2、意义:

解决代码的复用性。

3、代码:

父类

public class Student {
    public String name;
    public int age;
    private double grade;

    public void setGrade(double grade) {
        this.grade = grade;
    }

    public void ShowGrade() {
        System.out.println("姓名为:" + name + "年龄为" + age + "成绩为" + grade);
    }
}

子类

public class Graduate extends Student{

    public void test() {
        System.out.println("大学生" + name + "正在考数学");
    }
}
3、细节

a、子类继承了父类所有的属性和方法,非私有的属性和方法可以在子类直接访问,
但是私有的属性和方法不能再子类直接访问,要通过父类提供的公共方法区访问。

public class Student {
  public int score1 = 100;
  public int score2 = 80;
  private int score3 = 90;

  // 父亲提供一个public方法,返回score3
  public int getScore3() {
    return score3;
  }

  public void test1() {
    System.out.println("学生正在考试数学");
  }

  public void test2() {
    System.out.println("学生正在考试英语");
  }

  private void test3() {
    System.out.println("学生正在考试语文");
  }

  // 父亲提供一个public方法,调用test03
  public void callTest() {
    test3();
  }

}

b、子类必须调用父类的构造器,完成父类的初始化。

c、当创建子类对象时,不管使用子类哪个构造器,默认情况都会去调用父类的无参构造器。
  
如果父类没有提供无参构造器,则必须在子类的构造器中用supre去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译 不会通过。

d、如果希望指定去调用父类的某个构造器,则需要显示的调用一下:super(参数列表);

e、super在使用时,必须放在构造器第一行(super只能在构造器中使用)。

f、super()和this()都只能放在构造器第一行,因此两个方法不能共存在一个构造器中。

g、Java中所有类都是object类的子类。

h、父类构造器的调用不限于直接父类,将一直往上追溯到object类(顶级父类)。

i、子类最多只能继承一个父类,即Java中的单继承机制。如果要让A继承B类和C类呢?【A继承B,B继承C】。

j、不能滥用继承,子类和父类必须满足is-a的逻辑关系:如 猫是动物。

继承本质详解:

public class Extends {
	public static void main(String[] args) {
		Son son = new Son();
		/**
		此时需要根据查找关系来返回信息:
		a、查看子类是否有该属性。
		b、如果子类有,且可以访问,则返回信息。
		c、子类没有,看父类(父类有且可以访问返回父类,如果是私有则需要转换一下访问)。
		d、如果父类没有,则继续网上找,知道object。
		**/
		system.out.println(son.name);
		system.out.println(son.age);
		system.out.println(son.getSal);
	}
}

class Grandpa {
	String name = "yeye";
	int age = 60;
}

class Father extends Grandpa {
	String name = "baba"'
	int age = 30;
	private double salary = 10000;
	public double getSal() {
		return salary;
	}
}

class Son extends Father {
	String name = "erzi";
}

在这里插入图片描述

继承练习题1:

public class Extends {
	public static void main(String[] args) {
		C c = new C();  // 输出结果为:
		/*
		我是A类
		我是B类的有参构造
		我是C类的有参构造
		我是C类的无参构造
		*/
	}
}

class A {
	public A() {
		System.out.println("我是A类");
	}
}

class B extends A{
	public B() {
		System.out.println("我是B类的无参构造");
	}
	
	public B(String name) {
		 // super();     // 此处有个隐藏的 super调用父类无参构造
		System.out.println(name + "我是B类的有参构造");
	}
}

class C extends B{
	public C() {
		this("hello");    // 1、调用本类的有参构造
		System.out.println("我是C类的无参构造"):
	}
	public C(String name) {
		super("hahaha");  // 2、调用父类的有参构造
		System.out.println("我是C类的有参构造");
	}
}

继承练习题2:

public class Test {
	public static void main(String[] args) {
		PC pc = new PC("inter", 128, 512, "AUSS");
		pc.btand = "ASUS";
		pc.getPcDetails();
		NotePad notepad = new NotePad("inter", 128, 512,"black");
		notepad.color = "black";
	}
}

class Computer {
	String CPU;
	int Memory;
	int HardDisk;
	
	public Computer(String CPU, int Memory, int HardDisk) {
		this.CPU = CPU;
		this.Memory = Memory;
		this.HardDisk = HardDisk;
	}
	
	public String getDetails() {
		return CPU + "" + Memory + "" + HardDisk;
	}
}

class PC extends Computer {
	String btand;
	// 继承时会报错?因为子类会默认调用父类无参构造器,
	// 此时父类无参构造被覆盖了,子类要自己写
	public PC(String CPU, int Memory, int HardDisk, String btand) {
		super(CPU, Memory, HardDisk);  // 调用父类有参构造
		this.brand = brand;
	}		
	public void getPcDetails() {
		System.out.println(getDetails() + brand);
}

class NotePad extends Computer{
	String color;
	
	public PC(String CPU, int Memory, int HardDisk, String color) {
		super(CPU, Memory, HardDisk);
		this.color = color;
	}
}

super关键字:

1、定义:super代表父类的引用,用于访问父类的属性、方法、构造器。

2、基本用法:

a、用于访问父类的属性,但不能访问父类的private属性:super.属性名;

b、用于访问父类的方法,但不能访问父类private方法:super.方法名(参数列表);

c、访问父类的构造器:super(参数列表); 只可以放在构造器第一句,只能出现一句。

3、意义及细节:

a、super调用父类构造器的意义(分工明确,父类的属性由父类初始化,子类的属性由子类初始化)。

class NotePad extends Computer {
  private String color;

  public NotePad(String cpu, int memory, int disk, String color) {
    super(cpu, memory, disk);  // 父类由父类初始化
    this.color = color;   // 子类由子类自己初始化
  }
}

b、当子类和父类中的成员(属性和方法)重名时,为了访问父类成员,必须通过super,如果没有重名,则super、this以及直接访问都是一样的。
  在子类中使用:直接访问、this、super三者的区别:
  
直接访问和this:
1、先找本类,本类有,则调用。

2、本类没有,找父类(如果有且可以调用,则调用;如果有但是不能调用,则报错)。

3、如果父类没有,则继续往上找,直到object类。一直没有找到,提示不存在。

super:

1、直接找父类,不找本类。其余规则如上。

class Computer {
  private String cpu;
  private int memory;
  private int disk;
  public int num = 12;

  public Computer(String cpu, int memory, int disk) {
    this.cpu = cpu;
    this.memory = memory;
    this.disk = disk;
  }
}

class NotePad extends Computer {
  private String color;
  public int num = 1;

  public void test() {
    System.out.println(num);        // 1
    System.out.println(this.num);   // 1
    System.out.println(super.num);  // 12
  }
}

c、super访问不限于直接父类,如果爷爷类也有同名成员,也可以使用super去访问。如果多个上级类都有同名成员,遵循就近原则。

在这里插入图片描述

继承中的方法重写/覆盖:

1、定义:方法覆盖(重写)就是子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么就是子类方法覆盖了父类方法。

2、需要满足的条件:

a、子类的方法的形参列表方法名称要和父类的参数方法名称完全一样。

b、子类方法的返回类型要和父类一样或者是父类返回类型的子类:如父类返回类型是object,子类是String。

c、子类方法不可以缩小父类方法的访问权限:public > protected > 默认 > private。但是可以扩大,如父类是protected,子类可以一样或者是public

方法重写和方法重载的区别:

1、方法重载:Java中允许在同一个类中,多个同名方法的存在,到要求形参列表不一致。

2、方法重写:子类有一个方法,和父类的某个方法的名称、返回类型、参数一样,那么就是子类方法覆盖了父类方法。
在这里插入图片描述

多态:

一、多态概述:

1、多态是继封装、继承之后,面向对象的第三大特性。

2、多态现实意义理解:

现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是人,即出现两种形态。

Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。

3、多态的具体体现:

对象的多态:

a、一个对象的编译类型和运行类型可以不一致。

Animal animal = new Dog();  // animal的编译类型是Animal,运行类型是Dog

b、编译类型在定义对象时,就确定了,不可改变。

c、运行类型是可以变化的。

animal = new Cat(); // 编译类型仍然是Animal,运行类型变为了Cat.

d、编译类型看定义时 = 号左边,运行类型看 = 号右边

4、多态体现为父类引用可以指向子类对象

Master tom = new Master("Tom");
Dog dog = new Dog("大黄");
Bone bone = new Bone("骨头");
tom.feed(dog, bone);
Cat cat = new Cat("小花");
Fish fish = new Fish("小鱼");
tom.feed(cat, fish);

// 因为父类的引用可以指向子类的对象。所以:不管上面有几个对象,方法只用一个就行
// Animal animal = new Dog("大黄");
// Animal animal = new Cat("小花");
// Food food = new Bone("骨头");
// Food food = new FIsh("小鱼");
public void feed(Animal animal, Food food) {
	System.out.println(name + "给" + animal.getName() + "吃" + food.getFood());
}

多态细节

多态的前提条件:两个对象(类)必须有 继承关系.

1、多态的向上转型:

a、本质:父类的引用指向了子类的对象。
b、语法:父类 引用名 = new 子类类型();

c、特点:

①、编译类型看左边,运行类型看右边。
②、可以调用父类中所有的成员(方法、属性),要遵守访问权限。
③、不能调用子类中特有的成员。
④、最终运行效果看子类的具体实现。

Animal animal = new Cat();
// 1、可以调用父类中所有的成员(方法、属性),要遵守访问权限。
animal.animalEat();
animal.animalSleep();

// 2、不能调用子类中特有的成员。
// animal.catEat(); 错误
// 因为在编译阶段,能调用哪些成员由编译类型来决定,编译看左边 Animal,Animal没有catEat方法,不可调用。

// 3、最终运行效果看子类的具体实现,即调用方法时,从子类开始查找方法,子类有调用子类,子类没有找父类,有则调用,无则继续往上找。
animal.eat();  // 子类有eat方法,调用子类
animal.run();  // 子类无run方法,找父类。
/*
向上转型调用方法规则:

2、多态的向下转型:

a、语法:子类类型 引用名 = (子类类型) 父类引用;

Cat cat = (Cat) animal;

b、只能强转父类的引用,不能强转父类的对象。

Cat  cat = (Cat) Animal;    // 错误

c、要求父类的引用必须指向的是当前目标类型的对象。

即先要父类的引用指向子类的对象之后,才能再向下转型。

Animal animal = new Cat();   // 先有这个

Cat cat = (Cat) animal;   // 才能向下转型

d、向下转型后,可以调用子类中所有成员。

3、多态属性及instanceOf

a、属性没有重写之说,属性的值看编译类型。

Base base = new Sub();
Systm.out.println(base.count);  // 看编译类型Base的值

b、instanceOf比较操作符:用于判断对象的 运行类型 是否为某某某的类型或者子类型。

System.out.println(base instanceOf Base);  // true
System.out.println(base instanceOf Sub);  // base 运行类型为sub true

public class instanceOf {
  public static void main(String[] args) {
    BB bb = new BB();
    System.out.println(bb instanceof BB);  // true
    System.out.println(bb instanceof AA);  // true

    // aa的编译类型是AA,aa的运行类型是BB
    AA aa = new BB();
    // 下面这句话意思:aa的运行类型BB 是 AA 的类或者子类吗?
    System.out.println(aa instanceof AA);  // true
    // 下面这句话意思:aa的运行类型BB 是 BB 的类或者子类吗?
    System.out.println(aa instanceof BB);  // true
  }
}

class AA {}

4、动态绑定机制:

a、当调用对象的方法时,该方法会和该对象的内存地址/运行类型绑定。

b、当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用。

// 父类
class A {
public int i = 10;
public int sum() {
		return getI() + 10;
	}
public int sum1() {
		return i + 10;
	}
public int getI() {
		return i;
	}
}
// 子类
class B extends A {
	public int i = 20;
	public int getI() {
		return i;
	}
}
//主类:
A a = new B();
/*
1、子类找sum,找不到找父类。
2、父类有getI方法,子类也有那么调用哪个呢?该方法会和该对象的内存地址/运行类型绑定
运行类似是B,所以会调用子类B的getI方法。
*/
System.out.println(a.sum());    // 20 + 10 = 30
System.out.println(a.sum1());    // 属性没有动态绑定,就近原则 10 + 10 = 20
1、多态数组:

题目要求:一个person类。里面 name,age属性。一个student类。里面特有score属性和一个study方法,一个teacher类,里面特有salary属性,两个类都继承person类,分别调用里面的say()方法和各自特有方法。

Person persons[] = new Person[5];
persons[0] = new Person("jack", 20);
persons[1] = new Student("tom", 20, 100);
persons[2] = new Student("smith", 20, 100);
persons[3] = new Teacher("linda", 31, 22100);
persons[4] = new Teacher("king", 33, 22300);

for(int i = 0; i < persons.length; i++) {
	System.out.println(persons[i].say());  // say方法
	if(persons[i] instanceOf Student) {   // 使用了类型判断
		Student student = (Student)persons[i];  // 使用向下转型调用子类特有方法
		student.study();
	} else if(persons[i] instanceOf Teacher) {
		(Teacher)persons[i].teacher();
	}
}

2、多态参数:

方法的形参类型为父类类型,实参为子类类型:

public void feed(Animal animal, Food food) {  // 形参为父类
	System.out.println(name + "给" + animal.getName() + "吃" + food.getFood());
Master tom = new Master("Tom");
Dog dog = new Dog("大黄");    
Bone bone = new Bone("骨头");
tom.feed(dog, bone);            // 实参为子类
Cat cat = new Cat("小花");
Fish fish = new Fish("小鱼");
tom.feed(cat, fish);

在这里插入图片描述

题目要求:在这里插入图片描述

public class Main {
  public static void main(String[] args) {
    Ordinary tom = new Ordinary("tom", 2500);
    Manager milan = new Manager("milan", 5000, 200000);
    Main main = new Main();
    main.showEmpAnnual(tom);
    main.showEmpAnnual(milan);

    main.testWork(tom);
    main.testWork(milan);

  }

  // 方法:输出普通员工和经理的工资
  public void showEmpAnnual(Employee e) {
    System.out.println(e.getAnnual());
  }

  // 添加一个方法:如果是普通员工,则调用work方法,如果是经理,则调用manage方法
  // 使用 类型判断 + 向下转型   这里 e 就是 Employee的引用类型 Employee e =
  public void testWork(Employee e) {
    if (e instanceof Ordinary) {
      /*
      下面这句相当于:
      Ordinary ordinary = (Ordinary)e;
      ordinary.work;
      的简写
       * */
      ((Ordinary) e).work();  // 向下转型

    } else if (e instanceof Manager) {
      ((Manager) e).manage();
    } else {
      System.out.println("不处理");
    }
  }
}

object类:

object是所有类的超类。

1、 == 和 equals对比
①、 ==

a、== 是一个比较运算符,既可以判断基本类型,也可以判断引用类型。
b、如果判断基本类型,判断的是值是否相等;如果判断的是引用类型,判断的是地址是否相等,即判断是否是同一个对象。

②、equals:

a、是object类中的方法,只能判断引用类型。
b、默认判断地址是否相等,子类往往会重写该方法,用来判断内容是否相等。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值