面向对象的三大核心思想: 封装、继承、多态
使一种屏障, 防止对象属性被外界任意访问,提高对象属性的安全性
属性私有化
private 数据类型 属性名;
访问修饰符 | 含义 | 作用范围 |
---|---|---|
public | 公共的,公开的 | 任意位置都可访问 |
private | 私有的 | 只有本类内部可以访问 |
可以根据需求选择性的对属性进行私有化,但是通常情况下所有属性都应该私有化
提供取值赋值所需的getter\setter方法
getter: 取值. 有返回值,无参数
public 返回值类型 getXxx(){ ? ?return 属性名; } Xxx:对应属性名,首字母大写 ? ?如果属性是布尔类型,则该方法名为`isXxx`
返回值类型与对应属性保持一致
setter: 赋值. 没有返回值,有参数
public void setXxx(数据类型 属性名){ ? ?this.属性名=属性名; } Xxx:对应属性名,首字母大写
可以根据需求为私有属性添加getter或setter方法,但是通常情况下所有私有属性都应该有配套的getter和setter方法
一个getter或setter方法只能操作一个属性
给属性加上封装之后,必须通过调用getter和setter方法才能访问属性
取值: 对象名.getXxx()|对象名.isXxx() 赋值: 对象名.setXxx(实参)
package com.by.entity;
?
/**
* 银行卡: 卡号、密码、余额
*/
public class BankCard {
? ?private String cardID;
? ?private String password;
? ?private double balance;
?
? ?//取值
? ?public String getCardID(){
? ? ? ?return cardID;
? }
? ?//赋值
? ?public void setCardID(String cardID){
? ? ?// this.cardID = cardID;
? ? ? ?System.out.println("卡号不可更改");
? }
? ?public String getPassword(){
? ? ? ?return password;
? }
?
? ?public void setPassword(String password) {
? ? ? ?this.password = password;
? }
?
? ?public double getBalance() {
? ? ? ?return balance;
? }
?
? ?public void setBalance(double balance) {
? ? ? ?this.balance = balance;
? }
? ?
?
? ?public BankCard(){}
?
? ?public BankCard(String cardID, String password, double balance) {
? ? ? ?this.cardID = cardID;
? ? ? ?this.password = password;
? ? ? ?this.balance = balance;
? }
}
?
package com.by.test;
?
import com.by.entity.BankCard;
?
public class TestBankCard {
? ?public static void main(String[] args) {
? ? ? ?BankCard bc = new BankCard("628888888888888","411381",1000.0);
? ? ? /* bc.balance = 1000000000.0;
?
? ? ? ?System.out.println(bc.balance);
? ? ? ?System.out.println(bc.cardID);
? ? ? ?System.out.println(bc.password);*/
?
? ? ? ?//赋值
? ? ? ?bc.setCardID("627777777777777");
? ? ? ?//取值
? ? ? ?System.out.println(bc.getCardID());
?
? ? ? ?bc.setPassword("123456");
? ? ? ?System.out.println(bc.getPassword());
?
? ? ? ?bc.setBalance(100000.0);
? ? ? ?System.out.println(bc.getBalance());
?
? }
}
封装的步骤
getter、setter的区别
封装后的使用
将子类之间的共性进行抽取,生成父类.
在继承关系下,子类就可以默认拥有父类可别继承的内容
class 子类类名 extends 父类类名{
? ?
}
public class Animal {
? ?public String name;
? ?public int age;
? ?public String color;
?
? ?public void eat(){
? ? ? ?System.out.println("吃饭");
? }
? ?public void sleep(){
? ? ? ?System.out.println("睡觉");
? }
?
}
public class Dog extends Animal{
?
}
public class Cat extends Animal{
?
}
必须建立在is a关系之上
一个子类只能有一个直接父类 (单继承)
一个父类可以有多个直接子类
一个子类同时也可以是其他类的父类
子类中可以定义独有内容
父类无法访问子类的独有内容
子类可以继承拥有直接父类与间接父类中所有可被继承的内容
父类的私有内容子类无法直接继承访问
父类构造子类无法继承
子类的对象空间由父类内容+独有内容
构成
父类也是类,也应该按照要求进行属性的封装操作
package com.by.entity;
?
public class Animal {
? ?private String name;
? ?private int age;
? ?private String color;
?
? ?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 String getColor() {
? ? ? ?return color;
? }
?
? ?public void setColor(String color) {
? ? ? ?this.color = color;
? }
?
? ?public void eat(){
? ? ? ?System.out.println("吃饭");
? }
? ?private void sleep(){
? ? ? ?System.out.println("睡觉");
? }
?
}
父类封装之后,子类将无法直接访问父类属性,必须通过调用getter()|setter()
的方式堆父类属性进行访问
public class Test2 {
? ?public static void main(String[] args) {
? ? ? ?Dog dog = new Dog();
? ? ?// dog.sleep();
? ? ? ?/*dog.name = "小黑";
? ? ? ?dog.age = 2;
? ? ? ?dog.color = "白色";*/
? ? ? ?dog.setName("小黑");
? ? ? ?dog.setAge(2);
? ? ? ?dog.setColor("白色");
? }
}
又名方法覆盖
对从父类继承过来的方法进行方法体的重新书写,简称方法重写
返回值类型、方法名、参数列表必须与父类保持一致
访问修饰符必须与父类相同或者更宽
不能抛出比父类更大或更多的异常
子类进行方法重写之后,优先使用自身重写内容
父类的作用:
作为子类的共性抽取,解决子类之间的冗余问题
强制约束子类必须拥有某些特征和行为
子类对象的构建
给父子类属性分配空间,赋默认值
给父类属性赋初始值
执行父类构造
给子类属性赋初始值
执行子类构造
代表父类对象
指明调用父类对象的属性或方法
super.属性名 super.方法名(实参)
无法调用父类的私有属性
调用父类构造内容
必须写在子类构造有效代码第一行
根据参数列表决定执行的是哪个父类构造
this()和super()不可同时显式存在
执行子类构造内容之前必定先执行父类构造内容
当子类构造中未显式调用父类构造时,默认存在无参的super()
可以利用有参的super()直接在子类有参构造中给父类属性赋值
package com.by.entity;
?
public class Animal {
? ?private String name;
? ?private int age;
? ?private String color;
?
? ?public Animal() {
? }
?
? ?public Animal(String name, int age, String color) {
? ? ? ?this.name = name;
? ? ? ?this.age = age;
? ? ? ?this.color = color;
? }
? ?//省略getter\setter
?
}
?
public class Dog extends Animal{
? ?public Dog(){
? ? ?
? }
?
? ?public Dog(String name, int age, String color) {
? ? ? ?super(name, age, color);
? }
}
public class Test4 {
? ?public static void main(String[] args) {
? ? ? ?Dog dog = new Dog("小黑", 2, "白色");
? ? ? ?System.out.println(dog.getName());
? ? ? ?System.out.println(dog.getAge());
? ? ? ?System.out.println(dog.getColor());
? }
}
优化后的子类的有参构造:
访问修饰符 子类类名(父类的属性,独有的属性){ ? ?super(父类属性); ? ?this.独有属性名=独有属性名; ? ? ? }
控制内容可被访问的范围
本类 | 同包 | 非同包子类 | 非同包非子类 | |
---|---|---|---|---|
private(私有的) | √ | |||
default(默认的) | √ | √ | ||
protected(受保护的) | √ | √ | √ | |
public(公开的) | √ | √ | √ | √ |
都可以修饰属性、方法(普通方法、函数、构造)
都不可以修饰局部变量
只有public和default可以修饰掌握
继承的语法
继承的规则
方法重写的规则
有继承关系的对象创建过程
super关键字和this关键字的区别
四个访问修饰符及其作用范围
父类类型引用可以指向不同的子类对象
父类类名 引用名=new 子类类名(); 父类引用=子类对象;
建立在继承关系之上
实际创建的是子类对象
优先执行子类内容
父类引用无法访问子类的独有内容
编译失败
编译器关注的是引用类型,解释器关注的是实际对象类型
左边决定都能做什么,右边决定谁来做
大类型 引用名=小类型引用名|小类型对象;
父类是大类型,子类是小类型
小类型 引用名=(小类型)大类型引用名;
//利用多态创建Dog对象 ? ? ? ?Animal a = new Dog(); ? ? ? ?//将父类引用a强转为Dog引用 ? ? ? ?Dog dog = (Dog) a; ? ? ? // Dog的引用.lookDoor(); ? ? ? ?dog.lookDoor();
只能转向原本指向的子类类型
Animal a = new Dog(); Cat cat = (Cat) a; 错误!!
编译不报错,运行报错
java.lang.ClassCastException:类型转换异常
无父子类关系的子类之间不可进行强转
Dog d = new Dog(); Cat cat = (Cat) d; 错误!!
编译报错
用于容器: 将容器类型声明为大类型,则容器内部可以存放不同的小类型对象
Animal[] as = {new Dog(), new Dog(), new Cat(), new Cat()};
? ? ? ?//Animal as[0]=new Dog();
? ? ? ?//遍历数组,调用吃饭方法
? ? ? ?for (int i = 0; i < as.length; i++) {
? ? ? ? ? ?as[i].eat();
? ? ? }
用于参数: 将方法形参声明为大类型,则实参可以传入不同的小类型对象
public static void main(String[] args) {
? ? ? ?method1(new Dog());//狗吃大骨头
? ? ? ?method1(new Cat());//猫吃小鱼干
? }
?
? ?//定义一个函数,传入参数,可以执行出"狗吃大骨头"或"猫吃小鱼干"
? ?public static void method1(Animal a) {//Animal a=new Dog()//Animal a=new Cat()
? ? ? ?a.eat();
? }
用于返回值:将方法的返回值声明为大类型,则可以实际return不同的小类型对象
public static void main(String[] args) {
? ? ? ?//调用函数并接收返回值
? ? ? ?Animal a= method2(10);//Animal a=new Dog()
? ? ? ?a.eat();//狗吃大骨头
? ? ?// Dog d=(Dog)method2(10);
?
? }
? ?//定义一个函数,传入整型参数n,判断n的奇偶性,n为偶数返回Dog对象,n为奇数返回Cat对象
? ?public static Animal method2(int n){//Animal=new Dog()
? ? ? ?if (n % 2 == 0) {
? ? ? ? ? ?return new Dog();
? ? ? }
? ? ? ?return new Cat();
? }
判断当前对象是否与指定类型兼容
结果为布尔类型
引用名 instanceof 类名
public static void main(String[] args) {
? ? ? ?Animal[] as = {new Dog(), new Dog(), new Cat(), new Cat()};
? ? ? ?method(as);
? }
? ?//定义一个函数,传入一个Animal类型的数组,要求如果是Dog对象,执行"看门",如果是Cat对象,执行"猫吃小鱼干"
? ?public static void method(Animal[] as){
? ? ? ?for (int i = 0; i < as.length; i++) {
? ? ? ? ? ?if (as[i] instanceof Dog) {
? ? ? ? ? ? ? ?//将当前元素的类型强转为Dog类型
? ? ? ? ? ? ? ?Dog dog = (Dog) as[i];
? ? ? ? ? ? ? ?dog.lookDoor();
? ? ? ? ? } else {
? ? ? ? ? ? ? ?as[i].eat();
? ? ? ? ? }
? ? ? }
? }
子类对象可以被父类类型兼容
父类引用只能被所指向的子类类型兼容
子类类型无法兼容父类对象
public static void main(String[] args) {
? ? ? ?Dog d = new Dog();
? ? ? ?System.out.println(d instanceof Dog);//t
? ? ? ?System.out.println(d instanceof Animal);//t
?
? ? ? ?Dog jm = new JinMao();
? ? ? ?System.out.println(jm instanceof Dog);//t
? ? ? ?System.out.println(jm instanceof Animal);//t
?
? ? ? ?Animal a = new Dog();
? ? ? ?System.out.println(a instanceof Animal);//t
? ? ? ?System.out.println(a instanceof Dog);//t
? ? ? ?System.out.println(a instanceof Cat);//f
? ? ? ?System.out.println(a instanceof JinMao);//f
? }
减少代码冗余
将代码解耦合,提高代码扩展性
多态的概念
多态的使用
引用类型间的强转
多态的三个使用场景(用法)
instanceof关键字的作用和语法