JAVA里一直想实验的几个小问题
2016-04-04 00:28
603 查看
1、父类型引用指向子类型对象,只能调用父类有的方法,不能调用子类独有的方法。输出结果取决于子类实例到底什么样。
<span style="font-family:Microsoft YaHei;">package com.cry.practice; import static com.cry.utils.Print.*; class A { void f1() { println("a"); } } public class B extends A { void f1() { println("b"); } void f2() { println("bbbb"); } public static void main(String[] args) { A a = new B(); a.f1(); //! a.f2(); 这是错误的!A类型引用根本无法调用f2() } /* Output: b *///:~ } </span>
2、关于跨包继承,是否能重写,是否能调用的实验:
项目目录:A.java:
<span style="font-family:Microsoft YaHei;">package com.cry.another; import static com.cry.utils.Print.println; public class A { protected void f1(){ println("a"); } } </span>
B.java:
<span style="font-family:Microsoft YaHei;">package com.cry.practice; import com.cry.another.A; import static com.cry.utils.Print.*; public class B extends A { // 重写父类的方法总是可行的,不管父类中该方法是什么访问权限。 // 但要保证子类中该方法的访问权限大于等于父类 protected void f1() { println("b"); } public void f2() { f1(); //这样调用正确 //! A a = new A(); //! a.f1(); 错误,你不能调用另一个A类对象的f1(),因为f1()是protected的。 } public static void main(String[] args) { B b = new B(); b.f2(); } /* Output: b *///:~ } </span>
3、只要是用final修饰的数据,初始化之后就再也不能更改,不管是在什么地方,什么访问权限。只要是final修饰的变量在声明时就必须明确的初始化。
<span style="font-family:Microsoft YaHei;">class A { // final int v; //ERROR! private final int v1 = 1; protected final int v2 = 1; public final int v3 = 1; final int v4 = 1; public void f() { // v1 = 2; //ERROR! // v2 = 2; //ERROR! // v3 = 2; //ERROR! // v4 = 2; //ERROR! }</span>
4、父类的private成员,子类不能直接访问,但是如果父类有public修饰的getter/setter,子类则可以直接使用。比如下面的例子,可以说明,一个子类实例中确实包含一个名为val的int型数据实体,一个子类实例实际上包含一个父类实例在其中,但是父类的private修饰部分,子类却无法直接访问。面向对象的程序设计中,我们应当持这样的态度:“我们除了把private部分看成该类内部的实现结构之外,其他任何时候都不必考虑另一个类的private”。(注:JAVA的@Override注解似乎对这一问题有奇妙作用,日后研究)。或者可以说,private将类与类之间完全隔离开,哪怕它们是父子类。
<span style="font-family:Microsoft YaHei;">package com.cry.practice; import static com.cry.utils.Print.println; class A { private int val; public int getVal() { return val; } public void setVal(int val) { this.val = val; } } public class B extends A { // val = 5; //ERROR! void f() { // val = 5; //ERROR! setVal(1); } public static void main(String[] args) { B b = new B(); b.f(); println(b.getVal()); b.setVal(5); println(b.getVal()); } } /* Output: 1 5 *///:~</span>
5、final方法,子类根本不能重写,但子类可以调用。也就是说子类仍具有该final方法,只不过该方法的含义截止在父类那“一代”,子嗣无法修改。这满足了设计中这样的需求:锁定一个方法,以防止任何继承类修改它的含义,确保了该方法在继承中行为不变且不被覆盖。
<span style="font-family:Microsoft YaHei;">package com.cry.practice; import static com.cry.utils.Print.println; class A { public final void f(){ println("AAA"); } } public class B extends A{ // public void f(){} //ERROR!编译器直接报错,final方法不能被子类重写 public static void main(String[] args) { B b = new B(); b.f(); //但是子类可以使用这个final方法,这是没问题的。 } } /* Output: AAA *///:~</span>
6、private修饰的东西别的类就是不能访问到,子类也不能访问到,“同名重写覆盖”它,其实编译器只是认为子类有了一个新方法。
package com.cry.practice; import static com.cry.utils.Print.*; class Son extends Father{ public void f(){ println("son"); } } public class Father { private void f(){ println("father"); } public static void main(String[] args) { Father o1 = new Father(); Father o2 = new Son(); Son o3 = new Son(); o1.f(); o2.f(); o3.f(); } /* Output: father father son *///:~ }
7、关于抽象类的一个基本小例子, 注意其数据访问权限和初始化顺序。
记住三不相容:1、abstract不能与private同用,因为private不可被子类访问,也不可被重写(子类可以同名覆盖,但那相当于子类自己的新方法),而abstract是需要被重写的抽象方法。
2、abstract不能与final同用,因为final修饰的不能被重写,而abstract是需要被重写的抽象方法。
3、abstract不能与static同用,static修饰的方法归该类所有而非某个具体对象,并且也只归该类所有。如果该方法是protected或public,子类可以继承或调用,但不能重写(子类可以同名覆盖,但那相当于子类自己的新方法),而abstract表示期望被子类实现,所以不可同时使用。
package com.cry.practice; import static com.cry.utils.Print.*; //如果包含抽象方法,那这个类在声明时就必须用abstract修饰,否则IDE报错。 abstract class Student { public String type = "student"; public abstract void introduce(); } public class Tom extends Student{ public static void main(String[] args) { Tom tom = new Tom(); tom.introduce(); } //如果一个非抽象类继承了抽象类,那就必须给出抽象方法的定义。 @Override public void introduce() { //抽象类也是类,其中已经具体定义的数据成员可以访问,其子类的整个初始化过程也按标准进行。 println("Tom is a " + type); } /* Output: Tom is a student *///:~ }
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python动态类型的学习---引用的理解
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序