版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a724888/article/details/80048732
微信公众号【Java技术江湖】一位阿里 Java 工程师的技术小站。(关注公众号后回复”Java“即可领取 Java基础、进阶、项目和架构师等免费学习资料,更有数据库、分布式、微服务等热门技术学习视频,内容丰富,兼顾原理和实践,另外也将赠送作者原创的Java学习指南、Java程序员面试指南等干货资源。
本文主要介绍了final关键字的使用方法及原理
本文会结合虚拟机对引用和对象的不同处理来介绍三大特性的原理。
具体代码在我的GitHub中可以找到:
https://github.com/h2pl/MyTech
文章首发于我的个人博客:
https://h2pl.github.io/2018/04/22/javase1/
三大特性:继承 封装 多态
继承
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.smoke();
father.drive();
Son son1 = (Son) father;
son1.play();
son1.drive();
son1.smoke();
```
Father f1 = new Son();
Son s1 = (Son) f1;
s1.smoke();
s1.drive();
s1.play();
Father f2 = new Father();
Son s2 = (Son) f2;
s2.drive();
s2.smoke();
s2.play();
add(new LinkedList());
add(new ArrayList());
}
public static void add(List list) {
System.out.println(list);
}
总结:
向上转型和向下转型都是针对引用的转型,是编译期进行的转型,根据引用类型来判断使用哪个方法。并且在传入方法时会自动进行转型(有需要的话)。运行期将引用指向实例,如果是不安全的转型则会报错,若安全则继续执行方法。
编译期的静态分派:其实就是根据引用类型来调用对应方法。
public static void main(String[] args) {
Father father = new Son();
静态分派 a= new 静态分派();
a.play(father);
a.play((Son)father);
a.smoke(father);
}
public void smoke(Father father) {
System.out.println("father smoke");
}
public void play (Father father) {
System.out.println("father");
}
public void play (Son son) {
System.out.println("son");
}
方法重载优先级匹配
public static void main(String[] args) {
方法重载优先级匹配 a = new 方法重载优先级匹配();
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("...");
}
下一节具体介绍了基本数据类型以及常量池,具体请见:
https://blog.csdn.net/a724888/article/details/80041698