1.
红河ssl适用于网站、小程序/APP、API接口等需要进行数据传输应用场景,ssl证书未来市场广阔!成为成都创新互联的ssl证书销售渠道,可以享受市场价格4-6折优惠!如果有意向欢迎电话联系或者加微信:18982081108(备注:SSL证书合作)期待与您的合作!
引用a的类型是animal,是cat的父类。所以是“父类引用指向子类对象”。如果是“子类引用指向父类对象”,那应该写成
cat
a
=
new
animal();但这显然是不和逻辑的。
2.
你说的没错——“向上转型后,父类也只能调用父类已经有的方法”。但是子类如果覆盖了父类的方法,那么即使向上转型,方法的行为也表现为覆盖后的行为。这也是多态的一种体现。向上转型更多的用来体现一种编程上的“约定”。所有继承某个类或者实现某个接口的类,一定包含某个方法,这样在调用的时候,使得你也不必关系具体的实现细节,只要知道“这个类型中的某个方法能帮我完成工作”就可以了。
3.
向下转型,是“引用的类型”的变化,不是对象实例类型的变化。new什么,就是什么。不会因为向上或者向下转型而改变自己的类型。
4.
最后一个问题,不管向上还是向下转型,调用的都是实际类型中的那个方法。比如,animal
a
=
new
cat(); a.叫()。那这个叫就是cat类型实例中的“叫”方法。
呵呵,这个问题有意思了。
最大的用处是java的泛型编程,用处很大,java的集合类都是这样的,不过由于是向下转型,所以不是安全的。 下面是向下转型的例子:
子类转型成父类是向上转型,反过来说,父类转型成子类就是向下转型。但是,向下转型可能会带来一些问题:我们可以说麻雀是鸟,但不能说鸟就是麻雀。来看下面的例子:
A类:
package a.b;
public class A {
void aMthod() {
System.out.println("A method");
}
}
A的子类B:
package a.b;
public class B extends A {
void bMethod1() {
System.out.println("B method 1");
}
void bMethod2() {
System.out.println("B method 2");
}
}
C类:
package a.b;
public class C {
public static void main(String[] args) {
A a1 = new B(); // 向上转型
a1.aMthod(); // 调用父类aMthod(),a1遗失B类方法bMethod1()、bMethod2()
B b1 = (B) a1; // 向下转型,编译无错误,运行时无错误
b1.aMthod(); // 调用父类A方法
b1.bMethod1(); // 调用B类方法
b1.bMethod2(); // 调用B类方法
A a2 = new A();
B b2 = (B) a2; // 向下转型,编译无错误,运行时将出错
b2.aMthod();
b2.bMethod1();
b2.bMethod2();
}
}
从上面的代码我们可以得出这样一个结论:向下转型需要使用强制转换。运行C程序,控制台将输出:
Exception in thread "main" java.lang.ClassCastException: a.b.A cannot be cast to a.b.B at
a.b.C.main(C.java:14)
A method
A method
B method 1
B method 2
其实黑体部分的向下转型代码后的注释已经提示你将发生运行时错误。为什么前一句向下转型代码可以,而后一句代码却出错?这是因为a1指向一个子类B的对象,所以子类B的实例对象b1当然也可以指向a1。而a2是一个父类对象,子类对象b2不能指向父类对象a2。那么如何避免在执行向下转型时发生运行时ClassCastException异常?使用5.7.7节学过的instanceof就可以了。我们修改一下C类的代码:
A a2 = new A();
if (a2 instanceof B) {
B b2 = (B) a2;
b2.aMthod();
b2.bMethod1();
b2.bMethod2();
}
这样处理后,就不用担心类型转换时发生ClassCastException异常了。
你的myq本身就是通过new出来的,为什么需要转形呢?这里不存在任何需要转型的要求呀!
如果需要转型,在你调用myGet方法得到容器中的内容时是有转型需求的,因为你的myAdd方法添加的是Object,取出后也会是一个Object对象,即放入时是通过向上转型过的,如果取出后不进行向下转型,那么取出的对象只能看作是一个Object对象。
例如:
MyQueue myq = new MyQueue();
//假设有一个类Student中有一个方法getName得到学生的姓名信息;
Student student = new Student();
student.setName("张三");
myq.add(student);
//下面的这一种方式是必须向下转型的
Student stu = (Student)myq.myGet();
//下面的这种方式是不需要向下转型的
Object stu1 = myq.myGet();
//因为放入的都是作为Object看待的,取出的也是Object,只有转型成相应的对象才能进行
//如getName的操作
stu.getName();
//stu1.getName();错
下转型就是你上转型后才能做的操作;
例如:Map map = new HashMap(); 上转型
HashMap hmap = map;下转型
一般上转型都是实现接口编程的,减少两个类之间的偶合;
下转型一般是封装好的对象在解封而已。
首先还是给出解决办法吧:
package d;
import c.F;
public class A extends F
{
public static void main(String[] args)
{
A temp = new A();
F f = (F) temp;
if (f instanceof A)
{
A a = (A) f;
System.out.println(a.a());
}
}
输出结果:
你的要求无法实现。因为在你的例子中,f本身并不是由A类型向上转型为F得来的,所以本身是不会带有A的特性的,强制转换为A会失败,因为f在堆中的内容并未包括A类型的特性。即使你强制转换为A,A的新构造函数并不会调用,所有A额外的特性不会在堆中声明,所以会报错。Java中的向下转型是有条件的,你向下转型的对象必须原本在堆中包含了目的类型的内容,也就是说这个对象必须原本就是目的类型或其子类,只不过是通过向上转型现在不是目的类型或其子类罢了(但是堆中还是由该目的类型的特性存在,理解这一点很重要!)
有一个简单的办法验证这一点,就是你向下转型的时候,目的类型的构造函数并不会再一次调用,这样一来也就不会有目的类型的特性了,调用目的类型的特性自然而然就会失败了:
class Parent
{
public Parent()
{
System.out.println("This is Parent");
}
}
public class Child extends Parent
{
public Child()
{
System.out.println("This is Child");
}
public static void print()
{
System.out.println("print()");
}
public static void main(String[] args)
{
Child test1 = new Child();
Parent temp1 = (Parent) test1;
Child target1 = (Child) temp1;
target1.print();
Parent test2 = new Parent();
Child target2 = (Child) test2;
target2.print(); // 报错
}
}
输出结果:
还有不理解可以追问。