详细理解JAVA面向对象的封装,继承,多态,抽象

这篇文章主要介绍了Java基础之面向对象机制(多态、继承)底层实现,文中有非常详细的代码示例,对正在学习java的小伙伴们有非常好的帮助,需要的朋友可以参考下

目录

子类对象实例化的全过程

1.从结果上看:(继承性)

2.从过程上来看:

1.封装性

2.继承性

继承性的好处:

3.多态性

虚拟方法调用

4.抽象性

1.抽象类的特点:

2.天生的父类:抽象类

3.抽象方法

总结

创建类的对象 = 类的实例化 = 实例化类

类和对象的使用(面向对象思想落地的实现):

1.创建类,设计类的成员

2.创建类的对象

3.通过“对象.属性”或“对象.方法调用对象的结构

如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)

意味着,如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。

子类对象实例化的全过程

1.从结果上看:(继承性)

子类继承父类以后,就获取父类中声明的属性方法

创建子类的对象,在对空间中,就会加载所有父类中声明的属性

2.从过程上来看:

当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用父类的构造器,进而调用父类父类的构造器。直到调用java.lang.Object类中空参的构造器为止。正因为加载过所有的父类的结构,所以才可以看到内存中有父类的结构,子类对象才可以考虑进行调用

明确:虽然创建子类对象时,调用父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。

匿名对象

1. 理解:我们创建的对象,没有显式的赋给一个变量名,即为匿名对象

class Phone{ Phone p = new phone();//普通方式创建对象 p.sendEmail(); new Phone().sendEmail();//匿名对象只能直接调用方法 new Phone().price = 1999;//匿名对象调用属性 }

2.特征:匿名对象只能使用一次

3.匿名对象在开发中的使用

class Phone{ public static void main(String[] args){ PhoneMall mall = new PhoneMall(); //匿名对象的使用 mall.show(new Phone()); } } class PhoneMall{ public void show(Phone phone){ phone.sendEmail(); } }

1.封装性

封装性的体现:

我们将类的属性xxx私有化(private),同时,提供公共的(public)方法获取(getXxx)和设置属性

拓展:封装性的体现:A. 如上 B.不对外暴露的私有的方法 C.单例模式.....

封装性的体现,需要权限修饰符来配合。

1. Java规定的4中权限(从小到大排列):private、缺省、protected、public

2. 4种权限修饰符可以用来修饰类的内部结构:属性方法、构造器、内部类

3. 修饰类的话,只能使用:缺省、public; public类可以在任意地方被访问。

default类只可以被同一个包内部的类访问。

2.继承性

继承性的格式:class A extends B{}

A:子类、派生类、subclass

B:父类、超类、基类、superclass

体现:一旦子类A继承父类B以后,子类A中就获取父类B中声明的所有的属性方法

特别的,父类中声明为private的属性方法,子类继承父类以后,仍然认为获取父类中私有的结构。只是由于封装性的影响,使得子类不能直接调用父类的结构而已。

子类继承父类以后,还可以声明自己特有的属性方法,实现功能的扩展。子类和父类的关系,不同于子集和集合的关系。

Java中关于继承性的规定:

1.一个类可以被多个子类继承。

2.Java中类的单继承性,一个类只能有一个父类

3.子父类是相对的概念。

4.之类直接继承的父类,称为:直接父类;间接继承的父类称为:间接父类

5.子类继承父类以后,就获取了直接父类以及所有间接父类中生命的属性方法

----------

1.如果我们没有显示的声明一个列的父类的话,则此类继承于java.lang.Object类

2.所有的java类(除java.lang.Object类之外)都直接或间接的继承于java.lang.Object类

3.意味着,所有的java类具有java.lang.Object类声明的功能

继承性的好处:

减少了代码的冗余,提高了代码的复用性便于功能的扩展;为之后多态性的使用,提供了前提。

在使用子类实例时,如果我们想要使用某些父类属性方法,可以借助构造器和封装方法;如下:

public class Father{ //父类中的私有的属性 private double ownMoney = 2000;//私房钱 //父类中的受保护的属性 protected double money = 5000; //父类中的公开属性 public String name = "老张"; }

public class Son extends Father{ //子类中的独有属性 ... //使用构造器为属性赋值 public Son(String name,double money){ super.name = name; super.money = money; } //使用封装方法操作父类中的属性 public void setMoney(double money){ super.money = money; } public double getMoney(){ return super.money; } }

public class Test{ public static void main(String[] args){ //在test包中的Test类中创建Son实例 Son son = new Son("小张",3000);//为父类继承而来的属性赋值 //以下代码编译通过 double money = son.getMoney(); System.out.println(money); son.setMoney(money - 500); } }

从以上的例子看到:测试类对于字符类来说是一个处在不同包中的完全无关的类,在调用时会被权限修饰符所限制,所以这里明确一下:权限修饰符是根据类的搜在路径 与列之间的结构关系惊醒限定的,不是说在任意一个地方使用子类实例都能调用父类中的属性方法

3.多态性

1.理解多态性:可以理解为一个事物的多种形态。

2.何为多态性:

对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

3.多态的使用:虚拟方法调用

有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类方法

总结:编译,看左边;运行,看右边。

4.多态性的使用前提:A.存在子父类继承关系 B.子类重写父类方法 C.父类引用指向子类对象

5.对象的多态性,只适用于方法,不适用于属性(编译和运行都看左边)

5.1 若子类重写了父类方法,就意味着子类里定义的方法彻底覆盖了父类里的同名方法,系统将不可能把父类里的方法转移到子类中,编译看左边,运行看右边。

5.2 对于实例变量则不存在这样的现象,即使子类里定义了与父类完全相同的实例变量,这个实例变量依然不可能覆盖父类中定义的实例变量,编译运行都看左边。

6.多态的使用:当调用父类同名同参数的方法时,实际执行的是子类重写父类方法----->虚拟方法调用

虚拟方法调用

正常的方法调用

Person e = new Person(); e.getInfo(); Student e = new Student(); e.getInfo();

虚拟方法调用(多态情况下)

子类中定义了与父类同名同参数的方法,在多态情况下,将此时父类方法称为虚拟方法父类根据赋给它的不同子类对象,动态调用属于子类的该方法,这样的方法调用在编译期是无法确定的。

Person e = new Student(); e.getInfo();//调用Student类的getInfo()方法

编译时类型和运行时类型

编译时e为Person类型,而方法调用时在运行时确定的,所以调用的是Student类的getInfo()方法。------动态绑定

public class PersonTest{ public static void main(String[] args){ Person p2 = new Man(); Person p3 = new Woman(); p2.name = "Tom"; //不能调用子类所特有的方法属性;编译时,p2是Person类型。 // p2.earnMoney();//earnMoney()是子类Man()的方法 } }

有了对象的多态性以后,内存中实际上是加载了子类特有的属性方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的属性方法,子类特有的属性方法不能调用

如何才能调用子类特有的属性方法

答:向下转型,使用强制类型转换符。

Man m1 = (Man)p2; m1.earnMoney(); //使用强转时,可能出现ClassCastException的异常 Woman w1 = (Woman)p2;//p2是Man;两者并列关系 w1.goShopping();

解决这个问题的办法是先使用关键字(instanceof)判断一下!!!!! (会在下一篇博客关键字中介绍)

4.抽象性

背景:有两个在逻辑上看似相关的类,我们想要把他们联系起来,因为这样做可以提高效率,例如:矩形、圆形,都可以具有周长和面积两个方法,但是计算的方式完全不同,矩形和圆形之间肯定不能构成子父类的关系,那么只能是同时去继承一个父类。这时,就引出了抽象的概念。

1.抽象类的特点:

抽象类的本质依然是一个类,所以具备着一个普通类的所有功能包括构造方法等的定义,总结一下,抽象类具有以下的几个特点:

A. 抽象类由abstract修饰

B. 抽象类中允许出现抽象方法

C.抽象了不能通过构造器直接实例化

D.可以在抽象类中定义普通方法供子类继承。

public abstract class figure{ //定义计算周长的抽象方法:getC() //抽象方法,不能有方法主体 public abstract double getC(); }

2.天生的父类:抽象类

2.1 抽象类不能直接实例化(编译无法通过),是天生的父类

2.2 如果一个类继承了抽象类,那么必须重写父类中的抽象方法

2.3 如果抽象类中定义了构造方法,可以被子类调用或在实例化子类对象时执行

2.4 如果抽象类的子类依然是抽象类(需要用abstract声明),可以不重写抽象方法,将重写操作留给下一级子类

2.5 抽象类不能使用final关键字修饰,因为final 修饰的类是无法被继承

2.6 抽象类的匿名子类

public class PersonTest{ public static void main(String[] args){ method(new Student());//匿名对象 Worker worker = new Worker(); method1(worker);//非匿名的类非匿名的对象 method1(new Worker());//非匿名的类匿名的对象 //创建了一匿名子类的对象:p Person p = new Person(){ @Override public void eat(){ } } //创建匿名子类的匿名对象 method1(new Person()){ @Override public void eat(){ } } } } class Worker extends Person{ }

3.抽象方法

3.1 抽象类中的抽象方法只是声明,不包含方法

3.2 抽象方法不能用private修饰,因为抽象方法必须被子类实现(重写),而private 权限对于子类来说是不能访问的

3.3 一个类继承了一个抽象类,那么它必须全部重写抽象类中的抽象方法,当然也可以不全部重写,如果不重写全部抽 象方法则这个子类也必须是抽象类

3.4 构造方法,类方法(static修饰的方法)不能声明为抽象方法

总结

相关文章

HashMap是Java中最常用的集合类框架,也是Java语言中非常典型...
在EffectiveJava中的第 36条中建议 用 EnumSet 替代位字段,...
介绍 注解是JDK1.5版本开始引入的一个特性,用于对代码进行说...
介绍 LinkedList同时实现了List接口和Deque接口,也就是说它...
介绍 TreeSet和TreeMap在Java里有着相同的实现,前者仅仅是对...
HashMap为什么线程不安全 put的不安全 由于多线程对HashMap进...