黑马程序员技术交流社区

标题: 父类引用指向子类对象的问题 [打印本页]

作者: 武超    时间: 2011-12-5 19:14
标题: 父类引用指向子类对象的问题
本帖最后由 武超 于 2011-12-6 22:49 编辑

父类引用指向子类对象是这个样子的Fu f=new Zi();  可是这个父类引用指向子类对象意思是在用父类f调用方法是时候只能调用子类中包含的方法,而且还是父类中必须包含的方法,不能调用子类特有的方法,这样解释对吗?  
父类引用指向子类对象   这样的调用形式,在什么情况下使用?
作者: 段波    时间: 2011-12-5 19:54
  1. public class Test {

  2.        
  3. public static void main(String[] args) {
  4.         //这是多态的一些规范吧,用父类引用子类,调用的是子类覆盖父类的那个方法,即方法是可以覆盖的
  5.        
  6.                   Father myfather = new Son();
  7.                   Son son = new Son();
  8.         //而直接得到属性还是调到的父类的属性
  9.                   System.out.println(myfather.str );
  10.                   
  11.                   System.out.println(myfather.getStr());
  12.                   myfather.a();
  13.                   son.b();
  14.                     
  15.                 }

  16.         }
  17.         //父类:
  18. class Father {
  19.                  String str = "这是父类的属性";
  20.                 public String getStr(){
  21.                 return str;               
  22.                 };
  23.                 public void a(){
  24.                           System.out.print ("这是父类的方法");
  25.                 }
  26.         }
  27.         //子类:
  28. class Son extends Father {
  29.                  String str = "这是子类的属性";
  30.                 public String getStr(){
  31.                                 return str;               
  32.                 }
  33.                 public void a(){
  34.                           System.out.println("这是子类的方法");
  35.                 }       
  36.                 public void b(){
  37.                           System.out.println("这是子类的方法");
  38.                 }
  39.        

  40. }
复制代码
用代码运行一下就可以看得很明白
作者: fly51888    时间: 2011-12-5 20:00
本帖最后由 fly51888 于 2011-12-5 20:07 编辑

嗯,理解的很到位。如果想调用子类中特有的方法,则必须把需要调用子类方法的父类强制转换成子类。
如下代码:
public class App extends Person{

        public static void main(String[] args) {
               Person p = new App();
               p.change();
               ((App) p).sum();
               
               Person p2 = new Person();;
               p2.change();
        }
       
        public void change(){
                System.out.println("App");
        }
        public void sum(){
                System.out.println("sum");
        }
}

class Person{
       
        public void change(){
                System.out.println("Person");
        }
}
其中子类和父类都有change()函数,父类引用可以指向子类对象new App();如:p。
也可以指向父类对象new Person();如:p2。当引用指向子类时调用的是子类的方法,
当指向父类时调用的是父类的方法。当调用子类中的sum()函数时,此时p不能直接调用sum(),
必须将p转换成子类App时才能调用sum();函数。
作者: 刘海涛    时间: 2011-12-5 20:02
本帖最后由 刘海涛 于 2011-12-5 22:25 编辑

只能调用子类中包含的方法,而且还是父类中必须包含的方法,不能调用子类特有的方法,这样解释对吗?  
答:错了。只要子类都的方法就能调用。在编译的时候我们只能按照的规定只能调用父类的方法,你申明的是父类对象,编译器给你看到是父类的方法,但是new的是子类,实际的方法是存在的。我们可以通过反射或者强转去调用,new的是什么就是什么对象。

例如:看下面代码:



  1. /**
  2. * Person
  3. * @author Administrator
  4. *
  5. */

  6. public class Person extends Object {
  7.         private String name = "wangwu";
  8.        
  9.         public String getName() {
  10.                 return name;
  11.         }
  12.        
  13.         public void setName(String name) {
  14.                 this.name = name;
  15.         }
  16. }



  17. import java.lang.reflect.Method;

  18. public class Student extends Person {
  19.         private int age = 25;
  20.        
  21.         public int getAge() {
  22.                 return age;
  23.         }

  24.         public static void main(String[] args) throws Exception, NoSuchMethodException {
  25.                 Person person = new Student();
  26.                 System.out.println(person.getName());//默认
  27.                 System.out.println(((Student)person).getAge());//强转
  28.                
  29.                 /**
  30.                  * 下面是用反射的方式去执行
  31.                  */
  32.                 Method  method = person.getClass().getMethod("getAge", null);
  33.                 System.out.println(method.invoke(person, null));
  34.         }
  35. }

复制代码
父类引用指向子类对象   这样的调用形式,在什么情况下使用?
为什么要父类引用指向子类对象呢?例如,现在需求是要打印老师和学生的姓名,但是打印老师是:Teacher:

姓名,学生: Student :姓名  的形式打印,但是现在只有一个方法,不可以去判断是否是老师还是学生。这个时候我们需要用父类引用指向子类对象。
下面看代码:

  1. /**
  2. * Person
  3. * @author Administrator
  4. *
  5. */

  6. public class Person extends Object {
  7.         protected String name;
  8.        
  9.         public String getName() {
  10.                 return null;
  11.         }
  12.        
  13.         public void setName(String name) {
  14.                 this.name = name;
  15.         }
  16. }



  17. /**
  18. * Teacher
  19. * @author Administrator
  20. *
  21. */
  22. public class Teacher extends Person{
  23.        
  24.         public Teacher(String name) {
  25.                 setName(name);
  26.         }
  27.         @Override
  28.         public String getName() {
  29.                 return "Teacher:" + name;
  30.         }
  31. }



  32. /**
  33. * Student
  34. * @author Administrator
  35. *
  36. */
  37. public class Student extends Person {
  38.        
  39.         public Student(String name) {
  40.                 setName(name);
  41.         }
  42.        
  43.         @Override
  44.         public String getName() {
  45.                 return "Student:" + name;
  46.         }
  47.                  
  48.         public static void main(String[] args) throws Exception, NoSuchMethodException {
  49.                 Person student = new Student("wangwu");
  50.                 Person teacher = new Teacher("lisi");
  51.                 printPersonName(student);//输出Student:wangwu
  52.                 printPersonName(teacher);//输出Teacher:lisi
  53.           }
  54.        
  55.         public static void printPersonName(Person person) {
  56.                 System.out.println(person.getName());
  57.         }
  58. }

复制代码
上面的代码printPersonName()方法 只是打印person getName方法返回的字符串,但是不同的子类是有不同的输

出,这样我们不需要去判断是Student 还是Teacher ,具体的getName 由类自己去完成。这样给我们程序带来极

大的扩展性和维护性。

父类的getName返回为空,这个话毫无意义,这时候其实我们可以将它写出抽象的,具体的实现由子类去实现,

java提供的abstract 方法,如果类中有abstract的方法,特殊的方法不必写方法的实现,那么该类必须修饰为

abstract的,下面是改造后Person的代码:


  1. /**
  2. * Person
  3. * @author Administrator
  4. *
  5. */

  6. public abstract class Person extends Object {
  7.         protected String name;
  8.        
  9.         public abstract String getName();
  10.        
  11.         public void setName(String name) {
  12.                 this.name = name;
  13.         }
  14. }
复制代码
又例如台式电脑的PCI卡插槽,可以插独立声卡,独立显卡,独立网卡等等。在这样的情况下主板厂家需要知道每个卡是怎么执行的过程吗?不需要,生产卡的厂商只需要根据PCI的规范去生产就可以了。具体的实现由每个卡的厂商去实现。就像我们打印person 的getName,我们不需要知道是什么对象。

张老师的视频记得在基础视频中也写过PCI卡的类,你可以去看下,深刻的体会下。这样对后面的面向接口的编程更有帮助(其实就是特殊的父类而已)。


父类引用指向子类对象这样的调用形式当你只知道某种标准(就像Studnet和Teacher只知道getName方法),具体的实现需要子类去实现的时候我们会用到。

作者: 刘国辉    时间: 2011-12-5 21:25
父类引用指向子类对象,当调用父类的方法时,如果子类中有覆写,则调用子类的方法;没有则调用父类中的方法
另外子类中新增的方法此时不可见(如你在C类中增加一个方法F(),则r=c后,r.F()将出错)

A r;
B b = new B();
r = b;

此时r为A类型的引用,但它指向的对象是B类的对象,也就是子类对象

至于好处,你可以看看书,多态的用处
举个经典的例子吧:
Class Shape{
  public void draw()
  {
  }
}
Class A1 extends Shape
{
  public void draw()
  {
  }
}
Class A2 extends Shape
{
  public void draw()
  {
  }
}

每种形状都可以画,如三角形,正方形等等,但每种形状的画法又不一样
有如下方法
public void drawShape(Shape shape)
{
  shape.draw();
}
则该方法可以根据你实际传进来的对象调用相应的方法
比如:drawShape(new A1()),此时shape指向A1对象,则shape.draw()调用A1中的draw()
  drawShape(new A2()),此时shape指向A2对象, 则shape.draw()调用A2中的draw()

如果A1 A2中没有重写draw(),都将调用Shape中的 draw()

第一次回答这么长,好象有点乱,不知道你能看懂不
作者: 周敏2011nc    时间: 2011-12-6 11:18
继承的好处 : 通过继承,子类中不用写任何代码,就可拥有父类中公有的方法,如果你有自己的实现,可直接@Override,如果有新的方法,可直接写在子类中。
父类引用指向子类对象 :可以说它既是父类的对象,也是子类的对象,当然只能访问父类中公用的方法,如此你在使用父类引用指向子类对象时,应注意是否会用到子类所特有的方法,如果会用到就不应该使用。
作者: 刘海涛    时间: 2011-12-7 07:59
只能调用子类中包含的方法,而且还是父类中必须包含的方法,不能调用子类特有的方法,这样解释对吗?  
答:错了。只要子类都的方法就能调用。在编译的时候我们只能按照的规定只能调用父类的方法,你申明的是父类对象,编译器给你看到是父类的方法,但是new的是子类,实际的方法是存在的。我们可以通过反射或者强转去调用,new的是什么就是什么对象。

例如:看下面代码:



  1. /**
  2. * Person
  3. * @author Administrator
  4. *
  5. */

  6. public class Person extends Object {
  7.         private String name = "wangwu";
  8.        
  9.         public String getName() {
  10.                 return name;
  11.         }
  12.        
  13.         public void setName(String name) {
  14.                 this.name = name;
  15.         }
  16. }



  17. import java.lang.reflect.Method;

  18. public class Student extends Person {
  19.         private int age = 25;
  20.        
  21.         public int getAge() {
  22.                 return age;
  23.         }

  24.         public static void main(String[] args) throws Exception, NoSuchMethodException {
  25.                 Person person = new Student();
  26.                 System.out.println(person.getName());//默认
  27.                 System.out.println(((Student)person).getAge());//强转
  28.                
  29.                 /**
  30.                  * 下面是用反射的方式去执行
  31.                  */
  32.                 Method  method = person.getClass().getMethod("getAge", null);
  33.                 System.out.println(method.invoke(person, null));
  34.         }
  35. }

复制代码
父类引用指向子类对象   这样的调用形式,在什么情况下使用?
为什么要父类引用指向子类对象呢?例如,现在需求是要打印老师和学生的姓名,但是打印老师是:Teacher:

姓名,学生: Student :姓名  的形式打印,但是现在只有一个方法,不可以去判断是否是老师还是学生。这个时候我们需要用父类引用指向子类对象。
下面看代码:

  1. /**
  2. * Person
  3. * @author Administrator
  4. *
  5. */

  6. public class Person extends Object {
  7.         protected String name;
  8.        
  9.         public String getName() {
  10.                 return null;
  11.         }
  12.        
  13.         public void setName(String name) {
  14.                 this.name = name;
  15.         }
  16. }



  17. /**
  18. * Teacher
  19. * @author Administrator
  20. *
  21. */
  22. public class Teacher extends Person{
  23.        
  24.         public Teacher(String name) {
  25.                 setName(name);
  26.         }
  27.         @Override
  28.         public String getName() {
  29.                 return "Teacher:" + name;
  30.         }
  31. }



  32. /**
  33. * Student
  34. * @author Administrator
  35. *
  36. */
  37. public class Student extends Person {
  38.        
  39.         public Student(String name) {
  40.                 setName(name);
  41.         }
  42.        
  43.         @Override
  44.         public String getName() {
  45.                 return "Student:" + name;
  46.         }
  47.                  
  48.         public static void main(String[] args) throws Exception, NoSuchMethodException {
  49.                 Person student = new Student("wangwu");
  50.                 Person teacher = new Teacher("lisi");
  51.                 printPersonName(student);//输出Student:wangwu
  52.                 printPersonName(teacher);//输出Teacher:lisi
  53.           }
  54.        
  55.         public static void printPersonName(Person person) {
  56.                 System.out.println(person.getName());
  57.         }
  58. }

复制代码
上面的代码printPersonName()方法 只是打印person getName方法返回的字符串,但是不同的子类是有不同的输

出,这样我们不需要去判断是Student 还是Teacher ,具体的getName 由类自己去完成。这样给我们程序带来极

大的扩展性和维护性。

父类的getName返回为空,这个话毫无意义,这时候其实我们可以将它写出抽象的,具体的实现由子类去实现,

java提供的abstract 方法,如果类中有abstract的方法,特殊的方法不必写方法的实现,那么该类必须修饰为

abstract的,下面是改造后Person的代码:


  1. /**
  2. * Person
  3. * @author Administrator
  4. *
  5. */

  6. public abstract class Person extends Object {
  7.         protected String name;
  8.        
  9.         public abstract String getName();
  10.        
  11.         public void setName(String name) {
  12.                 this.name = name;
  13.         }
  14. }
复制代码
又例如台式电脑的PCI卡插槽,可以插独立声卡,独立显卡,独立网卡等等。在这样的情况下主板厂家需要知道每个卡是怎么执行的过程吗?不需要,生产卡的厂商只需要根据PCI的规范去生产就可以了。具体的实现由每个卡的厂商去实现。就像我们打印person 的getName,我们不需要知道是什么对象。

张老师的视频记得在基础视频中也写过PCI卡的类,你可以去看下,深刻的体会下。这样对后面的面向接口的编程更有帮助(其实就是特殊的父类而已)。


父类引用指向子类对象这样的调用形式当你只知道某种标准(就像Studnet和Teacher只知道getName方法),具体的实现需要子类去实现的时候我们会用到。




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2