2016-04-02 55 views
0

在Java中变量赋值期间是否有用途投射?在Java中赋值期间投射

例如,我有两个班,人员和学生,从人继承:

  • 人| -id:int
  • 学生 - >人员| -gpa:双

然后在主我有以下代码:

Student S = new Student(1, 4.00); 
Person P = (Student)S; 
System.out.println(P.getId() + " " + ((Student)P).getGpa()); 

的IntelliJ告诉我,在P = (Student)S铸造是多余的,如果我调用getGpa方法时,只投它的工作原理:

Student S = new Student(1, 4.00); 
Person P = S; 
System.out.println(P.getId() + " " + ((Student)P).getGpa()); 

但是,它给了我一个错误,如果我任职期间投下但不是当我再次打电话getGpa:

Student S = new Student(1, 4.00); 
Person P = (Student)S; 
System.out.println(P.getId() + " " + P.getGpa()); 

所以我的问题是 - 是否有一种情况下,在转让期间铸造是有用的?或者它是允许的,但总是多余的,因为你仍然必须告诉编译器每个方法调用你正在转换为子类型?

谢谢你的帮助。

+1

是关于在转换过程中关于转换的一般问题,还是关于将某些东西转换为原来的类型的问题。如果问题是“它是否已经是多余的东西”,答案是肯定的。 'S'是'Student'类型,所以将它转换为'Student'什么也不做。 'P'的类型是'Parent',所以将它转换为'Student'就可以做一些事情。 –

+0

这是多余的,因为学生*是-a *人,所以不需要演员。铸造任务的一种情况是'something =(Something)foo();'。 foo'返回一个Object。 – ChiefTwoPencils

+0

@DavidSchwartz我问的是在对象之间而不是基元之间进行投射 - 所以我认为你只能基于继承关系进行向上/向下投射。在这种情况下,我不会投射到相同的类型,我将投射到学生,以便我可以访问Student中的getGpa方法。所以有一点,但我特别要问,为什么甚至允许有人做'P =(Student)S',如果我不得不在调用getGpa方法时再次抛出它。 “ – allstar

回答

2

当您知道编译器没有的东西时,在赋值过程中投射并不是多余的。

当您指定Student对象Person变量,没有必要投,因为编译器知道从PersonStudent继承。但是如果将Person对象分配给Student变量,编译器不知道Person对象是否也是Student对象。

在这种情况下,您必须在赋值期间使用cast来告诉编译器,您知道这个特定的对象也是Student。您通常会首先使用instanceof进行验证。

if (P instanceof Student) { 
    Student S2 = (Student) P; // here the casting during assignment is required 
    S2.getGpa(); 
} 
+0

这是有道理的,但我有一个如何在实践中的问题。看起来P是Student实例的唯一原因是你实际上将一个Student对象赋给了一个Person变量。看起来更恰当的做法是将某些事物分配给它们相同的类型,并在不同地使用它时进行投射......为什么要做类似'Person P = new Student();'? – allstar

+0

您可能有一个“人员”对象的列表,您想迭代并仅对特定类型的对象执行某些操作。你也可能有一个函数接受一个'Person'对象,但如果它也是'Student',需要做一些特殊的事情。 – kichik

+0

@allstar,“为什么要做像P =新学生()的东西;?”因为你喜欢面向对象和多态的好处。 – ChiefTwoPencils

2

的IntelliJ告诉我,在P = (Student)S铸造是多余的

这是绝对正确的。 PersonStudent的基类,所以任何Student自动为Person

所以我的问题是 - 是否有一种情况下,在转让期间铸造是否有用?

不,它是多余的,它降低了代码的可读性。

即使您必须以统一的方式处理派生对象,例如将它们存储在基本类型的对象集合中,对基类的转换仍然毫无用处。当你确信你的A类的对象,事实上,一个子类B的一个对象,你不能表达对程序的知识以任何其他方式

List<Person> list = new ArrayList<>(); 
... 
Student student = new Student(); 
... 
list.add((Person)student); // <<= This is redundant, too. Don't do it. 
0

铸造是有用的,经常需要。

0

P = (Student)S的情况下,如果S是Student的实例,那么这样做没有好处,因为编译器已经知道这一点。

如果您后来有Student Q = P但是这不起作用,您将需要编写Student Q = (Student)P。演员被要求的原因是不能保证P实际上是一个学生(例如,它可能是一个导师,这也是一个人)。