数据抽象
一级目录
二级目录
三级目录
封装
使用private将属性进行封装(这个属性只在当前类的内部可见,对外部隐藏)。
使用public作用在方法上,提供调用的入口。
封装有两大特性:保护性和易用性
保护性
创建一个Person类,假设他的money属性是public(公共的),那么所有的人类对象都可以调用,也就是说你的钱任何人都可以花,这合理吗?
public class Person {
public String name;
public double money ;
}
class person {
public static void main(String[] args) {
Person person = new Person();
person.name = "xiaoming";
person.money = 100;
System.out.println("购买一瓶可乐");
person.money -= 3;
System.out.println(person.money);
}
}
为了避免属性被外部随意修改和访问,需要使用private将属性进行封装。若需访问和修改成员属性需要使用内部的getter和setter方法进行访问和修改。
易用性
通过程序对外界提供的方法来操控属性,可以更加灵活和安全。
比如:
public class Person {
public String name;
private double money;
public double setMoney(double money){
return this.money = money;
}
public double getMoney(){
return this.money;
}
}
public class xiaoMing {
public static void main(String[] args) {
Person person = new Person();
person.name = "xiaoming";
person.setMoney(100);
person.setMoney(person.getMoney() - 3);
System.out.println("购买一瓶可乐还剩下" + person.getMoney());
}
}
继承
面向对象编程最大的一个特点就是方法复用,假如有这样一组代码。
public class Animal {
public String name;
public void eat(String food){
System.out.println(this.name + "正在吃" +food);
}
}
public class Cat {
public String name;
public void eat(String food){
System.out.println(this.name +"正在吃" +name);
}
}
public class Dog {
public String name;
public void eat(String food){
System.out.println(this.name +"正在吃" +food);
}
}
这三个类代码完全一样
按道理来讲:
狗狗 是 动物
Dog is an Animal
猫 是 动物
Cat is an Animal
当类和类之间满足: 一个类 is a 另一个类 一定存在继承关系
当一个类继承了另一个类,另一个类中所有的属性和方法(包括静态属性和方法)子类就天然具备了
Java中使用extends表示类的继承
public class Dog extends Animal{
}
public class Cat extends Animal{
}
Dog(子类/派生类) extends Animal(父类/基类)
继承规则:
1.要能使用继承,必须满足is a关系
2.一个子类只能使用extends继承一个父类(单继承)
3.子类会继承父类的所有属性和方法,显示继承(public实行和方法可以直接使用),隐式继承(private属性和方法,子类其实也继承了这个方法但是无法直接使用)
protected访问权限
protected:当前类和其子类(不同包具有继承关系)内部可见
假设Animal是父类,其中的name属性是protected权限,person是Animal的子类,这时在test类(和Animal类没有继承关系)中创建一个person对象(Person per = new Person(); ),此时per这个对象无法使用那么这个属性,其原因就是per.name发生在test这个类中,protected权限只能在当前类和其子类中可见。
protected权限在同包中没有继承关系也可见
private < default < protected < public
既然default权限(包权限)小于protected权限,包权限可见的范围,protected一定包含。
所以protected权限:同包(不包含子包)下没有继承关系的类以及不同包下有继承关系的类之间都可见。
这里test和Anlmal在同一个包中
this关键字
表示当前对象的引用
修饰属性:表示直接从当前类中找同名属性
修饰方法:修饰构造方法、修饰普通方法,从当前类中 寻找
表示当前对象的引用
protected String name;
private int age;//隐式继承,子类没法直接使用该属性,必须通过父类提供的方法来操作
public Animal(){}//Animal的无参构造
public Animal(String name){
this();//this关键字调用无参构造
this.name = name;//this关键字调用类中同名属性
}
public Animal(String name,int age){
this(name);//this关键字调用有参构造
this.age = age;//this关键字调用类中同名属性
}
super关键字
修饰属性:表示直接从父类寻找同名属性
修饰方法:表示直接从父类寻找方法
1.super修饰属性
当有继承关系时,访问成员变量默认为使用this关键字
public class China extends Person{
public String name = "china";
public void fun(){
System.out.println(name);//默认为使用this
}
}
要想访问父类属性得加上super
public class China extends Person{
public String name = "china";
public void fun(){
System.out.println(super.name);
}
}
super先从直接父类中寻找同名属性,若不存在再向上寻找
不能使用super直接调用父类private权限的属性
this直接从当前类中找同名属性,若不存在再向上搜索
2.修饰构造方法
当产生子类对象时,默认先产生父类对象,若父类对象还有继承,继续向上先产生父类对象。
super修饰构造方法:
1.super(父类构造方法的参数);
2.super();//直接父类的无参构造,可写可不写
3.若父类中不存在无参构造,则子类构造方法的首行必须显式使用suoer(有参构造)
4.在一个构造方法中无法显示使用this()和super()同时出现
3.super修饰普通方法
1.和修饰属性一样直接从父类寻找同名方法
2.super不能指代当前父类对象的引用
final关键字
修饰属性表示属性值不能变–常量
修饰类,表示这个类无法被继承
final class Person
------Person无法被继承
组合关系
类和类除了继承关系之外还有组合关系,如果说还有就是毫无关系。
组合关系: School这个类有学生、老师,但老师和学生与学校不是继承关系。
School has student
School has teacher
这就是组合关系
多态
多态:一个引用可以表现出多种行为/特性 =>多态性
向上转型
Dog dog = new Dog();//最常见的
类名称 类引用 = new 该对象();
Animal animal = new Dog();
父类对象 父类引用 = new 子类对象();
总结:向上转型发生在有继承关系的类之间
假设现在没有向上转型:
class test1{
public static void main(String[] args) {
fun(new Animal());
fun(new Duck());
fun(new Bird());
}
//假设没有向上转型,有多少个子类就得重载多少次fun方法
public static void fun(Animal animal){}
public static void fun(Duck duck){}
public static void fun(Bird bird){}
}
有向上转型之后,最顶端的父类引用就可以指代所有的子类对象:
同一个引用(变量名称),同一个方法名称根据对象的不同表现出不同的行为—多态
fun中animal局部变量的引用调用eat方法时,当传入不同的对象时,表现出来了不同的eat方法行为,这就是多态性。
方法重写(override)
发生在有继承关系的类之间,子类定义了若干个和父类权限不同,其他完全相同的方法,这样的一组方法称之为方法重写。
比如:
方法重写:
看当前通过哪个类new的对象,若该类重写了相关方法,则调用的一定是重写后的方法。
若子类没有重写这个方法则调用父类的同名方法
当时发生重写时,子类权限必须大于等于父类权限(private < default < protected < public),但是不能是private权限。
方法重写只发生在普通方法中,静态方法也不行
假设Dog类中有一个扩展方法play(),这个方法Animal类不具备
类名称 引用名称 = new 类实例();
引用名称.方法名称();
能通过"."访问二点方法类名称说了算,能访问的这些方法必须都在类中定义过,编译器会先在类中查找是否包含指定方法。
至于这个方法到底表现出哪个类的样子,实例所在的方法说了算
向下转型
还是那个例子:假设Dog类中有一个扩展方法play(),这个方法Animal类不具备,但是此刻就像调用子类拓展的方法就必须还原为子类引用-----向下转型。
向下转型格式:
子类名称 子类引用 = (子类名称)父类引用;
Dog dog = (Dog)animal;
将父类引用强制转换为子类引用时:
子类 is a 父类 -----Dog is an animal
父类 is a 子类(不一定) — Animal is a Dog?
要发生向下转型,首先要发生向上转型。
当发生向下转型时会有风险----类型转换异常,可以使用instanceof关键字
引用名称 instanceof 类 ----返回布尔值,表示该引用指向的本质是不是该类的对象
小结:当方法接受一个类和当前类的子类,参数指定为相应的父类引用,发生的就是向上转型;当某个特殊的情况下,需要使用子类拓展方法,才需要将原本向上转型的引用向下转型还原为子类引用。
抽象类
若需要子类强制覆写方法,需要用到抽象类。
现实生活中有很多抽象类,这些类都是概念化的,没办法具体到某个实例来描述这一类对象共同的属性和行为。
比如说:人类–抽象类,因为没办法对应到具体某个或者某一类人
1.抽象类是普通类的“超集”,只比普通类多了一些抽象方法而已----普通类有的抽象类全有。
2.抽象方法所在的类必须是抽象类,子类(普通类)若继承了抽象类,必须覆写所有抽象方法。
3.Java中定义抽象类或者抽象方法使用abstract关键字。
1.抽象方法所在的类必须使用abstract声明为抽象类。
1.抽象方法指的是使用abstract关键字声明,只有函数声明,没有函数实现的方法,称为抽象方法。
2.Java中除了抽象方法没有方法体本地方法(不是抽象方法)也没有方法体。
public abstract class sharp {
public abstract void print();//只有方法声明,没有具体实现--延迟到子类实现
}
2.若一个类使用abstract声明为抽象类,无法直接通过该类实例化对象,哪怕该类中一个抽象方法都没有
当一个类是抽象类,不管他有没有抽象方法,这个类本身就是一个抽象的概念,没办法具体到某个特定的实例。(只能通过子类向上转型变为父类的引用)
Person per = new Person();//error
Person per = new China();//ok
3.子类继承了抽象类,就必须强制子类覆写抽象类中的所有抽象方法(子类是普通类),也满足单继承局限,一个子类只能extends一个抽象类。
4.抽象类是普通类的超集(普通类有的内容,抽象类都有),只比普通类多了一些抽象方法而已,抽象类虽然没法直接实例化对象,但也是可以存在构造方法(子类在实例化时,仍然遵从继承的规则,先调用父类(抽象类)的构造方法,而后调用子类构造方法)
接口
1.接口中只有全局常量和抽象方法
2.接口使用关键字interface声明,子类使用implement实现接口
一般来说,接口的使用表示两种场景:
1.接口表示具备某种能力/行为,子类实现接口时不是is a,而是具备这种能力或行为
比如说:游泳(能力)----Person(满足游泳接口)
2.接口表示一种规范或者标准
比如:“USB接口”
使用interface声明USB接口
public interface USB {
//插入
public abstract void PlugIn();
//工作
public abstract void Work();
}
子类KeyBoard使用implements实现接口,必须覆写所有抽象方法
public class KeyBoard implements USB{
@Override
public void PlugIn() {
System.out.println("安装驱动中");
}
@Override
public void Work() {
System.out.println("鼠标正常工作");
}
}
对于电脑这个类来说,它是USB规范的使用者,不关心到底哪个具体设备插入到我的电脑上,这要这个设备满足了USB接口,都能被电脑识别。
public class computer {
public static void main(String[] args) {
computer computer = new computer();
KeyBoard keyBoard = new KeyBoard();
computer.fun(keyBoard);
}
public void fun(USB usb){
usb.PlugIn();
usb.Work();
}
}
接口允许多实现,一个类可能具备多个能力,同时实现多个父类接口,若实现多个父接口,子类普通类,需要覆写所有的抽象方法