更多内容请关注微信公众号【Java技术江湖】

这是一位阿里 Java 工程师的技术小站,作者黄小斜,专注 Java 相关技术:SSM、SpringBoot、MySQL、分布式、中间件、集群、Linux、网络、多线程,偶尔讲点Docker、ELK,同时也分享技术干货和学习经验,致力于Java全栈开发!(关注公众号后回复”资料“即可领取 3T 免费技术学习资源以及我我原创的程序员校招指南、Java学习指南等资源)

本文会结合虚拟机对引用和对象的不同处理来介绍三大特性的原理。

三大特性:继承 封装 多态

继承

Java中的继承只能单继承,但是可以通过内部类继承其他类来实现多继承。

public class Son extends Father{
public void go () {
System.out.println("son go");
}
public void eat () {
System.out.println("son eat");
}
public void sleep() {
System.out.println("zzzzzz");
}
public void cook() {
//匿名内部类实现的多继承
new Mother().cook();
//内部类继承第二个父类来实现多继承
Mom mom = new Mom();
mom.cook();
}
private class Mom extends Mother {
@Override
public void cook() {
System.out.println("mom cook");
}
}
}

封装

封装主要是因为Java有访问权限的控制。public > protected > package = default > private。封装可以保护类中的信息,只提供想要被外界访问的信息。

类的访问范围

A、public	包内、包外,所有类中可见
B、protected 包内所有类可见,包外有继承关系的子类可见
(子类对象可调用)
C、(default)表示默认,不仅本类访问,而且是同包可。
D、private 仅在同一类中可见

多态

多态一般可以分为两种,一个是重写overwrite,一个是重载override。

重写是由于继承关系中的子类有一个和父类同名同参数的方法,会覆盖掉父类的方法。重载是因为一个同名方法可以传入多个参数组合。

注意,同名方法如果参数相同,即使返回值不同也是不能同时存在的,编译会出错。

从jvm实现的角度来看,重写又叫运行时多态,编译时看不出子类调用的是哪个方法,但是运行时操作数栈会先根据子类的引用去子类的类信息中查找方法,找不到的话再到父类的类信息中查找方法。
    而重载则是编译时多态,因为编译期就可以确定传入的参数组合,决定调用的具体方法是哪一个了。

向上转型和向下转型的解释 :
public static void main(String[] args) {
Son son = new Son();
//首先先明确一点,转型指的是左侧引用的改变。
//father引用类型是Father,指向Son实例,就是向上转型,既可以使用子类的方法,也可以使用父类的方法。
//向上转型,此时运行father的方法
Father father = son;
father.smoke();
//不能使用子类独有的方法。
// father.play();编译会报错
father.drive();
//Son类型的引用指向Father的实例,所以是向下转型,不能使用子类非重写的方法,可以使用父类的方法。
//向下转型,此时运行了son的方法
Son son1 = (Son) father;
//转型后就是一个正常的Son实例
son1.play();
son1.drive();
son1.smoke();
```
//因为向下转型之前必须先经历向上转型。 // 在向下转型过程中,分为两种情况:
//
// 情况一:如果父类引用的对象如果引用的是指向的子类对象,
// 那么在向下转型的过程中是安全的。也就是编译是不会出错误的。
//因为运行期Son实例确实有这些方法
Father f1 = new Son();
Son s1 = (Son) f1;
s1.smoke();
s1.drive();
s1.play();
// 情况二:如果父类引用的对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,
// 但是运行时会出现java.lang.ClassCastException错误。它可以使用instanceof来避免出错此类错误。
//因为运行期Father实例并没有这些方法。
Father f2 = new Father();
Son s2 = (Son) f2;
s2.drive();
s2.smoke();
s2.play();
//向下转型和向上转型的应用,有些人觉得这个操作没意义,其实可以用于方法参数中的类型聚合,然后具体操作再进行分解。
//比如add方法用List引用类型作为参数传入,传入具体类时经历了向下转型
add(new LinkedList());
add(new ArrayList()); //总结
//向上转型和向下转型都是针对引用的转型,是编译期进行的转型,根据引用类型来判断使用哪个方法
//并且在传入方法时会自动进行转型(有需要的话)。运行期将引用指向实例,如果是不安全的转型则会报错。
//若安全则继续执行方法。 }
public static void add(List list) {
System.out.println(list);
//在操作具体集合时又经历了向上转型
// ArrayList arr = (ArrayList) list;
// LinkedList link = (LinkedList) list;
}

总结:
向上转型和向下转型都是针对引用的转型,是编译期进行的转型,根据引用类型来判断使用哪个方法。并且在传入方法时会自动进行转型(有需要的话)。运行期将引用指向实例,如果是不安全的转型则会报错,若安全则继续执行方法。

编译期的静态分派:其实就是根据引用类型来调用对应方法。
public static void main(String[] args) {
Father father = new Son();
静态分派 a= new 静态分派(); //编译期确定引用类型为Father。
//所以调用的是第一个方法。
a.play(father);
//向下转型后,引用类型为Son,此时调用第二个方法。
//所以,编译期只确定了引用,运行期再进行实例化。
a.play((Son)father);
//当没有Son引用类型的方法时,会自动向上转型调用第一个方法。
a.smoke(father);
// }
public void smoke(Father father) {
System.out.println("father smoke");
}
public void play (Father father) {
System.out.println("father");
//father.drive();
}
public void play (Son son) {
System.out.println("son");
//son.drive();
}
方法重载优先级匹配
public static void main(String[] args) {
方法重载优先级匹配 a = new 方法重载优先级匹配();
//普通的重载一般就是同名方法不同参数。
//这里我们来讨论当同名方法只有一个参数时的情况。
//此时会调用char参数的方法。
//当没有char参数的方法。会调用int类型的方法,如果没有int就调用long
//即存在一个调用顺序char -> int -> long ->double -> ..。
//当没有基本类型对应的方法时,先自动装箱,调用包装类方法。
//如果没有包装类方法,则调用包装类实现的接口的方法。
//最后再调用持有多个参数的char...方法。
a.eat('a');
a.eat('a','c','b');
}
public void eat(short i) {
System.out.println("short");
}
public void eat(int i) {
System.out.println("int");
}
public void eat(double i) {
System.out.println("double");
}
public void eat(long i) {
System.out.println("long");
}
public void eat(Character c) {
System.out.println("Character");
}
public void eat(Comparable c) {
System.out.println("Comparable");
}
public void eat(char ... c) {
System.out.println(Arrays.toString(c));
System.out.println("...");
} // public void eat(char i) {
// System.out.println("char");
// }

下一节具体介绍了基本数据类型以及常量池,具体请见:

https://blog.csdn.net/a724888/article/details/80041698

微信公众号【程序员江湖】

作者黄小斜,斜杠青年,某985硕士,阿里 Java 研发工程师,于2018 年秋招拿到 BAT 头条、网易、滴滴等 8 个大厂 offer

个人擅长领域 :自学编程、技术校园招聘、软件工程考研(关注公众号后回复”资料“即可领取 3T 免费技术学习资源)

Java基础1:深入理解Java面向对象三大特性的更多相关文章

  1. Java入门系列(三)面向对象三大特性之封装、继承、多态

    面向对象综述 封装 封装的意义,在于明确标识出允许外部使用的所有成员函数和数据项,或者叫接口. 有了封装,就可以明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者:而外部调用者也可以知道 ...

  2. java基础强化——深入理解java注解(附简单ORM功能实现)

    目录 1.什么是注解 2. 注解的结构以及如何在运行时读取注解 2.1 注解的组成 2.2 注解的类层级结构 2.3 如何在运行时获得注解信息 3.几种元注解介绍 3.1 @Retention 3.2 ...

  3. [java基础]一文理解java多线程必备的sychronized关键字,从此不再混淆!

    java并发编程中最长用到的关键字就是synchronized了,这里讲解一下这个关键字的用法和容易混淆的地方. synchronized关键字涉及到锁的概念, 在java中,synchronized ...

  4. 理解PHP面向对象三大特性

    一.封装性 目的:保护类里面的数据,让类更安全, protected和private只能在类中或子类访问,通过public提供有限的接口供外部访问,封装是控制访问,而不是拒绝访问 封装关键字:publ ...

  5. JAVA基础——面向对象三大特性:封装、继承、多态

    JAVA面向对象三大特性详解 一.封装 1.概念: 将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问. 2.好处: 只能通过规定的方法访问数据. ...

  6. 夯实Java基础系列1:Java面向对象三大特性(基础篇)

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 [https://github.com/h2pl/Java-Tutorial](https: ...

  7. Java提高篇之理解java的三大特性——继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  8. 【转】java提高篇(二)-----理解java的三大特性之继承

    [转]java提高篇(二)-----理解java的三大特性之继承 原文地址:http://www.cnblogs.com/chenssy/p/3354884.html 在<Think in ja ...

  9. Java面向对象——三大特性

    Java面向对象——三大特性 摘要:本文主要介绍了面型对象的三大特性. 封装 什么是封装 封装,就是指一个类隐藏了对象的属性和实现细节,对自己的数据和方法进行访问权限控制,只允许某些类和对象进行访问和 ...

  10. [.net 面向对象编程基础] (11) 面向对象三大特性——封装

    [.net 面向对象编程基础] (11) 面向对象三大特性——封装 我们的课题是面向对象编程,前面主要介绍了面向对象的基础知识,而从这里开始才是面向对象的核心部分,即 面向对象的三大特性:封装.继承. ...

随机推荐

  1. idea中自动生成实体类

    找到生成实体的路径,找到Database数据表 找到指定的路径即可自动生成entity实体 在创建好的实体类内如此修改 之后的步骤都在脑子里  写给自己看的东西 哪里不会就记录哪里 test类(以前都 ...

  2. vue解决加载闪烁问题

    <!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>& ...

  3. BZOJ5412 : circle

    若仅保留这$k$个点仍然有环,那么显然无解. 否则设$A$表示这$k$个点的集合,$B$表示剩下的点的集合,因为是竞赛图,每个集合内部的拓扑关系是一条链,方便起见将所有点按照在所在集合的链上的位置进行 ...

  4. vector的用法小结(待补全

    1.vector的好处 支!持!删!除! 节!省!内!存! 2.一点基础的小操作 ①插入操作:v.push_back(x) 在尾部插入元素x: ②删除操作 : v.erase(x)删除地址为x的元素 ...

  5. VB洗牌算法产生随机数组

    算法图示: 运行效果: 详细代码: Option Explicit '洗16张牌(0-15),方便用十六进制显示 Dim Card() As Long Private Sub 洗牌() Dim i&a ...

  6. netcore应用程序部署程序到ubuntu

    运维需求:获取服务器的运行情况,是否CPU.内存较高等,上报到运维系统 环境:ubuntu16.04 工具::netcore2.1.supervisor 程序实现(代码就不贴了)参考:https:// ...

  7. 导航栏动态添加act属性

    最近做了一个网站,需要设置导航栏的act属性,这里需要用到addClass以及removeClass: $('#topName li').removeClass('active'); $(this). ...

  8. web项目部署到服务器中浏览器中显示乱码

    项目部署之后浏览器打开查看时页面乱码 这里可能需要修改一下tomcat配置文件,首先找到Tomcat的安装路径下的conf/server.xml文件,找到之后可以CTRL+F搜索如下的内容: < ...

  9. 检查对象是否为NULL或者为Empty

    不管是在Winform开发,还是在asp.net 开发中当从一个数据源中获取数据时你总是不知道这个数据的状态,这个时候总要对她进行一次判断,不过每次进行一次判断总是要写怎么一堆代码,时间长了,总感觉不 ...

  10. RDSS和RNSS

    RNSS英文全称Radio Navigation Satellite System,由用户接收卫星无线电导航信号,是一种卫星无线电导航业务,自主完成至少到4颗卫星的距离测量,进行用户位置,速度及航行参 ...