当前位置:天才代写 > tutorial > JAVA 教程 > 对Java多态性综合运用的探讨

对Java多态性综合运用的探讨

2017-11-11 08:00 星期六 所属: JAVA 教程 浏览:672

副标题#e#

或者各人java的多态问题,对上溯,下溯造型有了必然的观念,对protect和private各人想必也很清楚,可是,这几个个团结在一起,往往令人发生许多狐疑,在这里,我举一个例子,各人或者会觉察这篇文章对你来说照旧很有意义的:

例子一共有两个class. 大概呈现狐疑的处所我城市在后头一一表明。

A是一个父类,B担任A,而且实现了protectedTest(Object obj)要领.如下面所示:

B.java的源代码:

package cn.org.matrix.test;
import cn.org.matrix.test.A;
/**
* <p>Title: protect, private and upcasting </p>
* <p>Description: email:chris@matrix.org.cn</p>
* <p>Copyright: Matrix Copyright (c) 2003</p>
* <p>Company: Matrix.org.cn</p>
* @author chris
* @version 1.0,who use this example pls remain the declare
*/
public class B extends A
{
protected int protectedb = 0;
protected int protectedab = 0;
protected void protectedTest(Object obj)
{
System.out.println("in B.protectedTest(Object):" + obj);
}
}

A.java的源代码:

package cn.org.matrix.test;
import cn.org.matrix.test.B;
/**
* <p>Title: protect, private and upcasting </p>
* <p>Description: email:chris@matrix.org.cn</p>
* <p>Copyright: Matrix Copyright (c) 2003</p>
* <p>Company: Matrix.org.cn</p>
* @author chris
* @version 1.0,who use this example pls remain the declare
*/
public class A
{
protected int protecteda = 0;
protected int protectedab = 0;
private void privateTest()
{
System.out.println("in A.privateTest()");
}
protected void protectedTest(Object obj)
{
System.out.println("in A.protectedTest(Object):" + obj );
}
protected void protectedTest( String str )
{
System.out.println("in A.protectedTest(String):" + str);
}
public static void main (String[] args)
{
// Test A
A a1 = new A();
a1.privateTest();
// Test B
String helloStr = "Hello";
Object helloObj = helloStr;
B b1 = new B();
A a2 = b1; // 这里产生了什么?狐疑1
b1=a1; //编译错误,狐疑2
b1. privateTest(); //编译错误,狐疑3
b1.protectedTest(helloObj); //输出功效?狐疑4
b1.protectedTest(helloStr); //编译错误,狐疑5
a2.protectedTest(helloObj); //输出功效? 狐疑6
a2.protectedTest(helloStr); //输出功效?狐疑7 ?
}
}


#p#副标题#e#

下面,我来逐个表明每一处狐疑的处所:

狐疑1:

这里其实就是子类自动上溯造型到父类A。这里a2其实是指向了一个B范例的工具. 我们凡是都可以这样作: A a2=b1, 这样作的意思实际上就是让a2指向了一个范例B的工具-在这里就是b1了。

在java内里,关于跨类引用,有两条法则应该记着:

1. 假如a是类A的一个引用,那么,a可以指向类A的一个实例,可能说指向类A的一个子类。

2. 假如a是接口A的一个引用,那么,a必需指向实现了接口A的一个类的实例。

所以,按照这两个法则,我们就不难领略例子中的A a2 = b1是什么意思了。

狐疑2:

A a2 = b1是可以的,可是为什么b1=a1却是不可? 在这里,我们依然可以套用上面的两条法则,我们可以看到,b1是类B的一个引用,a1既不是类B的实例,也不是类B的子类的实例,所以直接b1=a1就呈现了编译错误.

假如确实需要举办这样的转化,我们可以这样作:b1=(B)a1; 举办强制转化,也就是下溯造型. 在java内里,上溯造型是自动举办的,可是下溯造型却不是,需要我们本身界说强制举办.

狐疑3:

b1. privateTest();编译不通过? 这是很显然的,你可以回首一下private的界说: 私有域和要领只能被界说该域或要领的类会见. 所以,在这里,b1不能会见A的要领privateTest(),纵然b1是A的子类的实例.

请看下面的例子:

public class A
{
private int two(int i) { return i; }
}
class Test extends A {
public static void main(String[] args) {
System.out.println(A.two(3));
}
}

System.out.println(A.two(3));这行编译堕落,显然,因为private要领不能在这个类之外被会见。

而protected则差异,我们回首一下protected的界说: 被掩护的域或要领只能被类自己、类的子类和同一 措施包中的类所会见。

下面是一个错误利用protected的例子:

package cn.org.matrix.test;
public class ProtectedTest {
protected void show() {
System.out.println("I am in protected method");
}
}
import cn.org.matrix.test.*;
public class Test {
public static void main (String[] args) {
ProtectedTest obj = new ProtectedTest();
obj.show();
}
}

因为会见权限问题,你会获得"show() has protected access in test.ProtectedTest"的堕落信息.

#p#副标题#e#

狐疑4:

#p#分页标题#e#

b1.protectedTest(helloObj); 输出的是"in B.protectedTest(Object):…" 这到底是为什么呢? 为什么jvm可以或许确定是输出B的要领而不是A的要领? 这就和jvm的运行机制有干系了. 我们上面提到了,a1是一个A范例的引用,可是指向了一个B范例的实例. 在这里,假如jvm按照引用的范例-在这里就是A 来界说挪用哪个要领的话,那么应该是挪用A的protectedTest(helloObj).

然后实际上不是这样的,因为jvm的动态编译本领,jvm会在run-time来抉择挪用哪一个method,而不是在compile time. 也就是所谓的late-binding(run-time)和early-binding(compile-time).

狐疑5:

b1.protectedTest(helloStr); 这里为什么会呈现编译错误? 他可以挪用类B的protectedTest(Object obj)要领啊,把helloStr上溯造型成一个object就行了啊..可能上溯造型到A然后挪用A的protectedTest(helloStr)要领。

问题的来源就在于此了,既然有两种选择,jvm应该选择那一种?这种不确定性假如交给jvm来动态抉择的话,势必带来措施的不确定性..固然java在其他的一些处所也有雷同的景象呈现,好比static变量的轮回界说造成的不确定性,可是,在这里,jvm照旧在编译阶段就办理了这个问题。

所以,我们会在这一步碰着编译错误: "reference to protectedTest is ambiguous; both method protectedTest(java.lang.String) in mytest.A and method protectedTest(java.lang.Object) in mytest.B match at line 46.

在这里,我们碰着的是显式的reference ambiguous错误,可是,有时候,隐式的reference ambiguous却往往是越发的危险。

在这里,我举个例子:

父类的 源代码:

public super
{
private void test(int i, long j);
{
System.out.println(i+"and"+j);
}
}

子类的源代码:

public sub
{
private void test(long j, int i);
{
System.out.println(i+"and"+j);
}
}

子类和父类都用有沟通名称的要领test,参数范例差异罢了.这种环境下,编译可以被通过.

可是假如你在别的一个类顶用到了如下代码:

Sub sb = new Sub();

sb.test(100, 3000);

你就会碰着编译错误,因为没有确定的指出3000的范例,所以造成reference ambiguous的错误了.

#p#副标题#e#

狐疑6:

a2.protectedTest(helloObj);

输出功效别离是:"in B.protectedTest(Object).." 颠末上面的表明,想必各人都能很清楚的知道为什么会有这两个输出功效了:a2.protectedTest(helloObj);因为jvm的late-binding,所以在run-time的时候,挪用了B类的要领,固然在编译期间a2只是一个父类A的引用范例。

狐疑7:

a2.protectedTest(helloStr); 为什么这里会输出" in A.protectedTest(Object)…"。为什么这里不会编译堕落?为什么b1. protectedTest(helloStr)会堕落而a2. protectedTest(helloStr)会堕落?我挪用了a2.equals(b1)和a2==b1获得的功效都是true啊?可是为什么这里出这个错误?

在这里,这个问题是最要害的,也是我们放到最厥后解答的原因。

首先,回首一下equals()和==的在java内里的观念,记得有一道scjp的题目:

题目:下面的哪些论述为真。

A. equals()要领鉴定引用值是否指向同一工具。

B. == 操纵符鉴定两个分立的工具的内容和范例是否一致。

C. equals()要领只有在两个工具的内容一致时返回true。

D. 类File重写要领equals()在两个分立的工具的内容和范例一致时返回true。

谜底是AD,严格来说这个问题的谜底是不确定的,因为equals()要领是可以被重载的,可是假如新类没有重写equals(),则该要领在两个变量指向同一工具时返回真. 实际上java也是推荐的是利用equals()要领来判定两个工具的内容是否一样,就像String类的equals()要领所做的那样,鉴定两个String工具的内容是否沟通。而==操纵符返回true的独一条件是两个变量指向同一工具。

在这里,我们不再深入的接头关于equals()和==的区别和观念。我们只需要知道,在我们的例子内里,无论是equals()和==都是一个寄义-就是引用值是否指向同一个工具(因为我们并没有重写equals()).

显然,我们在举办了a2=b1.这一步之后,a2和b1都是指向同一个工具。

既然指向同一个工具,为什么还要区别看待a2和b1?为什么a2就没有编译错误,而b1就要碰着reference ambiguous错误?

我们现看看jvm类型里的一段话:

"The Java Virtual Machine does not require any particular internal

#p#分页标题#e#

structure for objects. In Sun’s current implementation of the Java Virtual Machine, a reference to a class instance is a pointer to a handle that is itself a pair of pointers: one to a table containing the methods of the object and a pointer to the Class object that represents the type of the object, and the other to the memory allocated from the Java heap for the object data."

实际上就是说:在java虚拟机中,类实例的引用就是指向一个句柄(handle)的指针,这个句柄是一对指针:一个指针指向一张表格,实际上这个表格也有两个指针:一个指针指向一个包括了工具的要领表,别的一个指向类工具;另一个指针指向一块从java堆中为分派出来内存空间。

那么,在a2=b1的时候,到底产生了什么?

实际上,在a2=b1的时候,仍然是存在两个句柄,a2和b1,可是a2和b1拥有同一块数据内存块和差异的函数表。所以在a2.protectedTest(helloStr)的时候,jvm会从a2的函数内外找到protectedTest(String Str)要领,可是b1.protectedTest(helloStr)却会呈现编译错误,因为jvm从b1的函数内外找不到,然后就选择本身上溯造型照旧参数上溯造型呈现了ambiguous。这也是我们对这个问题的准确表明。

 

    关键字:

天才代写-代写联系方式