目录
一、封装性:
描述:封装之前学习过方法,方法就是一种封装,在面向对象的封装性中,本质上也是讲方法的封装
封装性:在面向对象中,不要直接调属性,而是通过set/get方法进行封装
好处:结构更清晰,复用性更强,安全性更强
通过封装,将属性设为私有的,外部不能直接修改属性值(从源头上规避直接调用属性),只能通过公开的方法来操作私有的变量,提高了信息的隐蔽性和安全性
用类实现封装,用封装实现高内聚低耦合
封装步骤:
1.编写set/get方法,注意规范写法,set用于赋值,get用于取值
2.属性私有化
二、继承性
1.概述
一个类如果想要具备另外一个类的属性和方法,那么可以通过继承,实现得到父类的资源
Object:所有类的父类
重合点(特征和行为接近)越多,越接近直接父类
重合点越少,越接近Object类
2.为什么要继承?
例:当有两个动物猫、狗,它们都有姓名属性、吃饭、睡觉的方法,如果分开写两个类,每个类都去写这些属性和方法的话,太麻烦,而且代码很冗余,一样的属性和方法写两次。
所以这个时候可以抽象出来他们共有的的东西形成一个父类,如:写一个动物类,这个类有属性和方法,那么我们就可以将猫狗类去继承这个动物类,就可以继承这个动物类的属性和方法,那么这些属性和方法我们只需要在子类中继续调用就行。
好处:减少代码量、减少冗余、提高代码的复用性、提高扩展性
提高扩展性:
当子类继承父类的时候,如果对父类的方法不满意则可以重写父类中的方法。如:动物类有个方法是吃,但是狗类继承了动物类,可以重写这个方法,使方法具有子类的特性
案例:
class Animal{
String name;
int age;
public void eat() {
System.out.println(name+"正在吃...");
}
public void sleep() {
System.out.println(name+"正在睡...");
}
}
class Dog extends Animal{ //Dog继承Animal
String color;
public void run() {
System.out.println(name+"正在跑");
}
}
class Bird extends Animal{ //Bird继承Animal
String color;
public void fly() {
System.out.println(name+"正在飞");
}
}
class Fish extends Animal{ //Fish继承Animal
public void swim() {
System.out.println(name+"正在游");
}
}
public class Test1 {
public static void main(String[] args) {
Dog dog = new Dog();
dog.name = "旺财"; //调父类的属性
dog.color = "黄色"; //调自身独有属性
dog.run(); //调自身独有方法
dog.sleep(); //调父类方法
System.out.println("--------------");
Bird bird = new Bird();
bird.name = "八哥";
bird.fly();
bird.eat();
System.out.println("--------------");
Fish fish = new Fish();
fish.name = "小金";
fish.swim();
fish.sleep();
}
}
3.继承的特点
在java中只有单继承,没有多继承
但是又多级继承,就是说子类继承的父类还可以又父类(子类可以有爷爷类)
父类可以调用父类的父类资源,不能调用子类的资源
子类可以调用父类资源以及它爷爷的资源
案例:
//案例:爷爷有1000万;爸爸有一辆跑车;儿子有一辆玩具车
class GrandFather{
String name;
public void haveMoney() {
System.out.println(name+"拥有1000万");
}
}
class Father extends GrandFather{ //多级继承
public void haveCar() {
System.out.println(name+"有一辆跑车");
}
}
class Son extends Father/*,GrandFather*/{//没有多继承
public void haveToy() {
System.out.println(name+"有一辆玩具车");
}
}
public class Test2 {
public static void main(String[] args) {
Father father = new Father();
father.name = "大三"; //调爷爷类的属性
father.haveMoney(); //调爷爷类的方法
father.haveCar(); //调自身的方法
//father.haveToy(); //不能调子类的方法
System.out.println("===============");
Son son = new Son();
son.name = "小三";
son.haveMoney(); //调爷爷类的方法
son.haveCar(); //调父类的方法
son.haveToy(); //调自身的方法
}
}
4.继承的限制
私有的成员不能被继承
构造方法没有继承性
不同包的default权限,没有继承性
构造方法虽然没有继承性,但是当子类继承了父类的时候,实例化子类的时候,优先去调用父类的构造函数,然后才是调用子类的构造函数------也就是说子类虽然没有继承父类构造函数,但是可以调用父类的构造函数
5.super用法
super表示父类对象;和this有点类似,只是this表示当前对象
在应用上也和this类似;super可以调用属性,方法,构造方法
super VS this
this调属性:调当前对象的属性;如果当前类没有,则根据继承性,调父类属性
this调方法:调当前对象的方法;如果当前类没有,则根据继承性,调父类方法
this调构造方法:调当前类的构造方法
super调属性:调父类的属性
super调方法:调父类的方法
super调构造方法:调父类的构造方法
案例:
//super调属性:
class Person{
String name="刘亦菲";
}
class Student extends Person{
String name="凤姐";
public void show() {
System.out.println(name); //凤姐-先调自身,自身没有才调父类属性
System.out.println(this.name); //凤姐-先调自身,自身没有才调父类属性
System.out.println(super.name); //刘亦菲-调父类属性
}
}
public class Test1 {
public static void main(String[] args) {
new Student().show();
}
}
//super调方法:调的是父类的方法
class Animal{
public void show() {
System.out.println("父类的show方法");
}
}
class Dog extends Animal{
@Override
public void show() {
super.show(); //先调父类的方法
System.out.println("子类的show方法");
}
}
public class Test2 {
public static void main(String[] args) {
new Dog().show();
}
}
在构造方法中,默认首句会出现super(); 先调用父类无参构造。
为什么这么设计?
原因是,实例化对象的过程是父类资源+子类资源;否则就不会有继承的特点(调父类属性和方法)因为子类继承了父类,所以子类不仅有自身的资源而且还有父类的资源,所以在实例化子类对象的时候,要加载父类的资源,这样就能调用父类的资源,然后再加载自身的资源,这样就实现了继承。
案例:
class A{
public A() {
System.out.println("父类A的无参构造");
}
public A(int a) {
System.out.println("父类A的带参构造");
}
}
class B extends A{
public B() {
//super();
System.out.println("子类B的无参构造");
}
public B(int a) {
//super(a); //调父类带参 this和super在构造方法中不能共存
this(); //A无参 B无参 B带参
System.out.println("子类B的带参构造");
}
}
public class Test3 {
public static void main(String[] args) {
//new B(); //父类A无参; 子类B无参
new B(66); //父类A无参; 子类B带参
}
}
三、多态
1.什么是多态
从字面意思可以知道多态就是多种形态的表现形式。多态的前提其实就是继承或接口,正是因为有了继承、接口,子类继承父类然后去重写父类的方法、实现类实现接口然后重写接口的方法才体现出多态。
如:一个动物有吃的方法,而狗继承了动物类,重写吃方法后表现为吃骨头
而猫继承了动物类,重写吃方法后表现为吃猫粮
这就是继承后重写方法所体现出来的多态,多种形态(实现类实现接口同理)
程序中的多态:将子类对象当成父类看待,这就是多态;换句话说,父类引用指向子类对象,即形成多态
例如:Animal an = new Dog(); //多态核心
多态应用:父类引用指向子类对象,即可调用父类的方法,不能调用子类独有的方法
案例:
class Animal{
public void eat() {
System.out.println("动物正在吃...");
}
}
class Dog extends Animal{
public void bark() {
System.out.println("旺财正在汪汪汪...");
}
}
public class Test1 {
public static void main(String[] args) {
Animal animal = new Dog(); //多态核心
animal.eat(); //父类引用可调用父类方法
//当成父类看待,则调不了子类方法
//animal.bark(); //父类引用不能调子类独有方法
}
}
2.多态的几种形式
直接引用多态
//直接引用多态的方式调用重写方法:
//案例:将猫当成宠物看待,可调用宠物的吃的方法;如果猫有不同吃的行为,则优先调用
class Pet{
public void eat() {
System.out.println("宠物正在吃东西...");
}
}
class Cat extends Pet{
@Override
public void eat() {
System.out.println("猫正在吃...");
}
}
public class Test2 {
public static void main(String[] args) {
Pet pet = new Cat(); //父类引用指向子类对象,优先调子类重写方法
pet.eat(); //子类有重写方法,优先调子类方法
}
}
传参多态
//案例:主人喂养宠物,猫,狗都是宠物,都有各自吃的行为
//分析:类-宠物类(父),猫类(子),狗类(子),主人类(第三方类); 方法-吃,喂养
//问题:两个宠物,就需要写两个喂养的方法;后面扩展更多宠物,则继续增加喂养方法
//面向对象设计原则:ocp原则-开闭原则
//o-open:对外部扩展的类持开放状态-例如可扩展很多宠物类(扩展性)
//c-close:对内部修改的代码持关闭状态-例如-主人喂养行为不要增加(维护性,灵活性)
//多态的好处:使程序的扩展性,可维护性更强
class Pet{ //宠物类
public void eat() { //吃
System.out.println("宠物正在吃...");
}
}
class Dog extends Pet{
@Override
public void eat() { //重写吃
System.out.println("旺财正在吃...");
}
}
class Cat extends Pet{
@Override
public void eat() { //重写吃
System.out.println("加菲猫正在吃...");
}
}
class Master{ //主人类
//--------重载方法--------
/*
public void feed(Dog dog) {
dog.eat(); //狗在吃
}
public void feed(Cat cat) {
cat.eat(); //猫在吃
}*/
//传参实现的多态
public void feed(Pet pet) {//Pet pet = new Dog(); 多态
pet.eat(); //谁传给我,就调谁的 (不要看谁调的,要看谁传的)
}
}
public class Test1 {
public static void main(String[] args) {
Master master = new Master();
master.feed(new Dog()); //1.主人喂养狗
master.feed(new Cat()); //2.主人喂养猫
}
}
返回值多态
//返回值多态:调用方法返回子类对象,由父类引用接收;构成返回值多态
//案例:主人购买宠物;根据标识购买不同宠物:1.买鸟 2.买狗
//分析:类-主人类(第三方类);宠物类(父),鸟,狗(子) 方法:购买
class Pet{
public void eat() {
System.out.println("宠物在吃东西");
}
}
class Bird extends Pet{
@Override
public void eat() {
System.out.println("鸟正在吃东西");
}
}
class Dog extends Pet{
@Override
public void eat() {
System.out.println("狗正在吃东西");
}
}
class Master{
public Pet bug(int type) {
if(type==1) {
return new Bird();
}else if(type==2) {
return new Dog();
}else {
return null;
}
}
}
public class Test1 {
public static void main(String[] args) {
Master master = new Master();
Pet pet = master.bug(1); //返回子类对象;用父类Pet接收,形成多态
pet.eat(); //调子类重写方法
}
}
四、抽象类
1.概述
某些类具有某种方法,但不能具体实现,这样的方法叫抽象方法;所在的类就是抽象类。
例如:动物类(抽象类)----叫(抽象方法)
这样的抽象类我们无法具体化(不能实例化对象),可以交给子类具体化以及具体实现。
好处:
更自然地使用多态; 抽象方法可以当成模板来使用
抽象方法一定在抽象类,抽象类中不一定都是抽象方法
抽象类细节说明:
1.抽象类能否具体化 不能被实例化
2.抽象类能否有构造方法 因为子类构造方法可以调:super(),可以有
3.有抽象方法的类一定是抽象类吗? 是的
4.抽象类是否必须有抽象方法? 可以没有抽象方法
5.抽象类是否可以有非抽象方法? 可以有
6.父类为抽象类,子类是否必须要重写抽象方法? 不是必须的,也可以将子类变为抽象类
2.直接引用多态
案例:
abstract class Animal{ //抽象类
public abstract void bark(); //抽象方法--模板
public Animal() {} //可以有构造方法
public void eat() { //非抽象方法
}
}
//The type Dog must implement the inherited abstract method Animal.bark()
//报错处理方案:1.重写父类方法 2.把自身变抽象
/*abstract*/ class Dog extends Animal{
@Override
public void bark() {
System.out.println("大黄正在汪汪汪的叫...");
}
public void run() {
System.out.println("大黄正在跑....");
}
}
public class Test1 {
public static void main(String[] args) {
//Animal animal = new Animal(); //抽象类是不能具体化的
Animal animal = new Dog(); //抽象类就是为多态而生 抽象类直接引用多态
animal.bark(); //抽象类指向子类对象,可调用子类重写方法
//animal.run(); //不可以调子类独有的方法
//结论:后续使用继承的多态,基本都是抽象类实现多态;因为应用更明确,且父类方法不会太浪费
}
}
3.传参多态
案例:
//案例:主人喂养宠物,猫,猪都是宠物,都有各自吃的行为
//分析-宠物类(父),猫类(子),猪类(子),主人类(第三方类); 方法-吃,喂养:
abstract class Pet{ //抽象类
public abstract void eat(); //抽象方法
}
class Cat extends Pet{
@Override
public void eat() {
System.out.println("加菲猫正在吃...");
}
}
class Pig extends Pet{
@Override
public void eat() {
System.out.println("佩奇正在吃...");
}
}
class Master{
public void feed(Pet pet) { //传参多态
pet.eat();
}
}
public class Test2 {
public static void main(String[] args) {
Master master = new Master();
master.feed(new Cat()); //主人喂猫
master.feed(new Pig()); //主人喂猪
}
}
4.返回值多态
案例:
//返回值多态:调用方法返回子类对象,由父类引用接收;构成返回值多态
//案例:小孩购买玩具;根据标识购买不同玩具:1.买鸟 2.买鱼
//分析:类-小孩类(第三方类);玩具类(父),鸟,鱼(子) 方法:购买
abstract class Toy{
public abstract void start();
}
class Bird extends Toy{
@Override
public void start() {
System.out.println("玩具鸟正在发射..");
}
}
class Fish extends Toy{
@Override
public void start() {
System.out.println("玩具鱼正在发射..");
}
}
class Boy{
public Toy buy(int type) {
if(type==1) {
return new Bird();
}else if(type==3) {
return new Fish();
}else {
return null;
}
}
}
public class Test3 {
public static void main(String[] args) {
Boy boy = new Boy();
Toy toy = boy.buy(1);
toy.start();
}
}
五、引用类型转换
在基本类型中有类型转换:转的前提是类型要兼容;然后低类型可转高类型,高类型也能转低类型(强转)
在引用类型中,一样有类型转换:转换的前提是必须建立关系:父子关系(后面的接口也可转)
在引用类型的转换中,有向上转和向下转两种
1.基本转换
向上转---子类转父类,默认转(多态核心)
向下转---父类转子类,强转
案例:
//父类Animal与子类Dog之间的相互转换:
class Animal{
}
class Dog extends Animal{
}
public class Test1 {
public static void main(String[] args) {
Animal animal = new Dog(); //向上转-默认转(多态核心)
Dog dog = (Dog)animal; //向下转-强转
}
}
2.强转隐患及处理
强转的隐患:类型转换异常
可以使用instanceof处理类型转换的异常 instanceof-做判断的关键字
instanceof不是真实处理问题,而是规避异常
案例:
//父类与子类之间的转换:
class Pet{ //父类
}
class Bird extends Pet{ //子类
}
class Pig extends Pet{ //子类
}
public class Test2 {
public static void main(String[] args) {
Pet pet = new Bird();
//类型转换异常:Bird cannot be cast to Pig 鸟不能转成猪
//Pig pig = (Pig) pet; //向下转-强转(出现隐患)
//可以使用instanceof处理类型转换的异常 instanceof-做判断的关键字
// if (args instanceof type) { args: 变量 type:类型
if (pet instanceof Pig) {
Pig pig = (Pig) pet;
System.out.println("pet的本质类型是Pig");
}else if(pet instanceof Bird) {
Bird bird = (Bird)pet;
System.out.println("pet的本质类型是Bird");
}
//结论:instanceof不是真实处理问题,而是规避异常
}
}
六、总结
1.多态
继承是前提
多态核心-父类引用指向子类对象;(重点)
应用:可调用父类方法,不能调子类独有方法
2.多态中的重写(重点)
直接引用多态;
传参多态--多态优势(需要第三方类); 返回值多态(需要第三方类)
3.引用类型转换
基本转:向上转(默认转),向下转(强转)
强转隐患处理--instanceof
4.抽象类(重点)
和父类多态类似;只是抽象类更常用于多态中
理解抽象类细节,好处
应用:直接引用,传参多态,返回值多态