在内存分配上没有区别,都是Dog对象,但是第一种写法Animal dog = new Dog(); dog只能调用父类Animal里的方法和属性,要想使用子类Dog里的有父类Animal里没有的方法就比须向下转型,也就是强制转换(Dog)dog一下。 第二种写法Dog dog = new Dog(); 就没有这个问题了。
狗继承了动物!动物 = new 狗;这里只能调用动物的属性方法,如果狗继承动物后重写了动物里的一些方法,那么就调用狗重写的那个方法. 但是不能调用狗的自己的方法,比如狗欺负猫这个方法,动物没有,只有狗有.狗 = new 狗;可以调用狗从动物继承过来的方法,还包括它自己的特性的方法
1.内存分配 Animal dog = new Dog(); 在堆区建立Dog对象,在栈区建立Animal引用,该引用指向Dog对象 Dog dog = new Dog(); 在堆区建立Dog对象,在栈区建立Dog引用,该引用指向Dog对象 2.使用 Animal dog = new Dog();可以使用未被重写的非privateAnimal方法,Animal上非private所有属性,以及在Dog中重写Animal的方法 Dog dog = new Dog(); 可以使用Dog ,Animal的非 private属性和方法
6楼的说得挺全拉!是多态的问题! 项目中更多见的是第一种!用父类作为引用 new 其子类!
大家说的我看懂了,但是照你们这么说 Dog dog = new Dog();似乎更好些(既可以调用父类的,又可以调用自己的,程序员想调什么就调什么多方便),但程序中 Animal dog = new Dog();用的更多。为什么呢???
java中对象类型的变量可以指向自己的实例或它的任何子类的实例 Animal dog = new Dog(); // 父类的引用指向子类的事例,dog变量的类型是父类的,可以把Dog看成是Animal 他们的区别就不难理解 Animal的引用可以指向其他子类,而这样就可以用到JAVA的动态帮定, 把父类的引用作为参数可以自动识别子类的方法,这样就不必要去写每个子类的具体逻辑public class Test { public static void main(String[] args) { Animal animal = new Dog("dog"); System.out.println(getAnimalInfo(animal)); animal = new Cat("Cat"); System.out.println(getAnimalInfo(animal)); }
public static String getAnimalInfo(Animal animal) { return "This is " + animal.getName(); } }abstract class Animal { public abstract String getName(); }class Dog extends Animal{
private String name = "";
public Dog(String name) { this.name = name; }
public String getName() { return this.name; } }class Cat extends Animal { private String name = "";
public Cat(String name) { this.name = name; }
public String getName() { return this.name; } }如果不用多态,那每个子类都要写自己的逻辑,但子类很多很复杂的时候,多态的优点就体现出来了
因为有了继承,才有了子类和父类的定义。 从继承的语义上讲,是子类继承父类,所以子类拥有父类的非private变量和方法。 有了继承,也就出现多态性。从而有了Animal dog = new Dog(); ,这是多态的重要表现。 这是一种常用的写法,这种代码更灵活,如果哪天不想使用Dog中的方法,可以在编写一个类, 继承Animal,来替换Dog的操作。
楼主是个爱思考的人啊。上面的这些留言,我感觉只是说出了一个方面。 这些留言,似乎并没有解答出楼主在8楼所提出的疑问。我就自不量力,抛砖引玉一下:Animal dog = new Dog(); 在很多时候更好一些,比如还有一个Animal的子类Cat, 在后续代码中,如果需要让dog变量引用Cat对象的话, 那么可以直接:dog = new Cat(); 因为dog是父类型的,它可以引用子类型的对象。Dog dog = new Dog(); 这样声明的话,dog只可以引用Dog对象。我觉得这体现了解耦的思想。 面向接口编程,意义也就在这里。
Animal dog = new Dog(); 和 Dog dog = new Dog(); 就这两行来讨论是没什么意义的.class A { private: Animal FAnimal; ,,,,, }对象A调用 FAnimal.XXX 时才显示出多态的威力了. (如果换成IAnimal可能更好)
Animal dog = new Dog(); //你的朋友送给你一个宠物,很显然是个动物,对吧,他和他带来的礼物还在路上,你就迫不及待的想看看是个什么东东 dog.狗刨式游泳(); //然而你还不知道这个动物是什么,你怎么敢说这个动物会狗刨式游泳呢? //如果你把它扔到你家门口的小池塘子里面,你敢保证你的朋友不会跟你绝交吗? //所以 dog.狗刨式游泳();在编译的时候会报错,为了程序的安全,不能访问对象不存在的特性Dog dog = new Dog(); //你守在村东口,老远老远你就看到了,你确信就是一只小狗 dog.狗刨式游泳(); //把它扔到你家门口的小池塘子里,它游得可欢实了
Animal dog = new Dog(); //你的朋友送给你一个宠物,很显然是个动物,对吧,他和他带来的礼物还在路上,你就迫不及待的想看看是个什么东东 dog.狗刨式游泳(); //然而你还不知道这个动物是什么,你怎么敢说这个动物会狗刨式游泳呢? //如果你把它扔到你家门口的小池塘子里面,你敢保证你的朋友不会跟你绝交吗? //所以 dog.狗刨式游泳();在编译的时候会报错,为了程序的安全,不能访问对象不存在的特性 Dog dog = new Dog(); //你守在村东口,老远老远你就看到了,你确信就是一只小狗 dog.狗刨式游泳(); //把它扔到你家门口的小池塘子里,它游得可欢实
就是多态!和接口,和抽象类一样的思想! 就象String 类重写equals方法一样 A c=new A(); B d=new B(); String a="a"; String b="b"; System.out.println(c.equals(d));//调用的是基类equals方法 System.out.println(a.equals(b));//调用的派生类String类 equals方法
这个答案很有道理,我只简单说一说, int i = 9; 我们是现声明整型变量int ,名字就i , 定义了一个数字 9 ,从右往左看,将数字9赋予变量iAnimal dog = new Dog(); 左边Animal dog 同上面一样是声明 Animal 这个类的对象 dog 右边 new Dog()是实例化一个对象,这一步有一个调用 Dog 类构造函数初始化这个类的过程,一般就是给这个类的属性赋值; 并且左边这个引用指向右边 Animal dog = new Dog(); Dog dog = new Dog(); 只看右边都是在实例化Dog这个对象,调用构造函数初始化属性 再看左边,前者是声明父类对象,后者是声明子类对象, 前者是一个向上转型,Animal dog 引用指向new Dog();子类对象当成父类对象,只能调用父类的成员,如果子类重写了父类的方法就根据这个引用指向调用子类重写的这个方法(这个方法就是覆盖override)。这个调用过程就称为“动态绑定”。
区别是,楼主将一个动物接口(父类、抽象类)的实现(子类)“狗”的实例赋给了动物这个接口,由于向上还原的原因,楼主将只可以使用动物接口(父类、抽象类)的动作,而不可以使用“狗”独有的动作。 什么是“向上还原”或“向上转型”楼主可查java基础级的书籍,在继承和多态等章节均可找到,或是百度谷歌一下 关于区别楼主可以写两个类,类a有方法A()B(),类B有同名同参同返回值的A()B()和独有的C(),如果楼主采用 Animal dog = new Dog(); 的方式,是无法使用C()的,而Dog dog = new Dog();就完全可以。
就是多态的问题,建议LZ看看孙慧琴的《java面向对象编程》多态将得蛮好。
这是一种上转型机制, Dog 类 继承了 Animal类。 Animal dog = new Dog(); 也就是说你可以用Animal 内的方法,丢掉了Dog 类的新方法。 和 Dog dog = new Dog(); 你可以用Dog 内的方法,也可以用Animal类内的方法,私有方法除外。
前者 只可以使用Animal中的方法 后者 可以使用DOG的方法
4L说的太直接了 狗继承了动物! 动物 = new 狗; 这里只能调用动物的属性方法,如果狗继承动物后重写了动物里的一些方法,那么就调用狗重写的那个方法. 但是不能调用狗的自己的方法,比如狗欺负猫这个方法,动物没有,只有狗有. 狗 = new 狗; 可以调用狗从动物继承过来的方法,还包括它自己的特性的方法
灵活,扩展 public Person createFactory(personEnum type){ Person person=null;//如果返回子类对象 switch(type){ case STUDENT: person=new Student(); break; case TEACHER: person=new Teacher(); break; } return person; } 前台 PersonFactory pf=new PersonFactory(); Person person=null; person=pf.createFactory(personEnum.STUDENT);//子类对象接收会怎样 person.Run();
我也觉得21楼说的正是楼主想要的,不过再补充一点: Animal dog = new Dog(); 在这个声明之后可以:Dog d=(Dog)dog;//此时d可以用dog对象的成员了
恩,这个气氛不错..... Tag !
Animal dog = new Dog(); 和 Dog dog = new Dog(); 第一种是父类的引用指向子类对象,第二种是纯粹的子类的实例化,第一种可以实现多态,第二种不可以
大家看看这段代码。按大家的意思:a.test应该打印Base才对啊class A { void method(){System.out.println("Base");} //父类的method方法 void test(){method();} //父类的特有test方法 } public class B extends A{ void method(){System.out.println("Sub");} //重写了父类的方法 public static void main(String[] args) { A a=new B(); //父类的引用指向子类的对象 a.test(); // 打印 Sub } }
大家看看这段代码。按大家的意思:a.test应该打印Base才对啊class A { void method(){System.out.println("Base");} //父类的method方法 void test(){method();} //父类的特有test方法 } public class B extends A{ void method(){System.out.println("Sub");} //重写了父类的方法 public static void main(String[] args) { A a=new B(); //父类的引用指向子类的对象 a.test(); // 打印 Sub } }
继承就是可以用父类的引用来new一个子类的对象
这种用法是为了产生多态
当调用父类中的方法时,如果子类有覆盖这个方法的话,那么调用的就是子类的这个方法。
第二种写法Dog dog = new Dog(); 就没有这个问题了。
但是不能调用狗的自己的方法,比如狗欺负猫这个方法,动物没有,只有狗有.狗 = new 狗;可以调用狗从动物继承过来的方法,还包括它自己的特性的方法
Animal dog = new Dog(); 在堆区建立Dog对象,在栈区建立Animal引用,该引用指向Dog对象
Dog dog = new Dog(); 在堆区建立Dog对象,在栈区建立Dog引用,该引用指向Dog对象
2.使用 Animal dog = new Dog();可以使用未被重写的非privateAnimal方法,Animal上非private所有属性,以及在Dog中重写Animal的方法 Dog dog = new Dog(); 可以使用Dog ,Animal的非 private属性和方法
项目中更多见的是第一种!用父类作为引用 new 其子类!
Animal dog = new Dog(); // 父类的引用指向子类的事例,dog变量的类型是父类的,可以把Dog看成是Animal
他们的区别就不难理解 Animal的引用可以指向其他子类,而这样就可以用到JAVA的动态帮定,
把父类的引用作为参数可以自动识别子类的方法,这样就不必要去写每个子类的具体逻辑public class Test {
public static void main(String[] args) {
Animal animal = new Dog("dog");
System.out.println(getAnimalInfo(animal));
animal = new Cat("Cat");
System.out.println(getAnimalInfo(animal));
}
public static String getAnimalInfo(Animal animal) {
return "This is " + animal.getName();
}
}abstract class Animal {
public abstract String getName();
}class Dog extends Animal{
private String name = "";
public Dog(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}class Cat extends Animal {
private String name = "";
public Cat(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}如果不用多态,那每个子类都要写自己的逻辑,但子类很多很复杂的时候,多态的优点就体现出来了
1.对象不变;(改变的是主观认识)
2.对于对象的调用只能限于编译时类型的方法,如调用运行时类型方法报错。
在上面的例子中:Animal a=new Dog();对象a的编译时类型为Animal,运行时类型为dog。
注意:编译时类型一定要为运行时类型的父类或者同类型。
对于语句:Dog d=(Dog)a。将d强制声明为a类型,此时d为Dog(),此时d就可以调用运行时类型。注意:a和d指向同一对象。
3.动态类型判定实际调用的方法。即它调用覆盖后的方法。
从继承的语义上讲,是子类继承父类,所以子类拥有父类的非private变量和方法。
有了继承,也就出现多态性。从而有了Animal dog = new Dog(); ,这是多态的重要表现。
这是一种常用的写法,这种代码更灵活,如果哪天不想使用Dog中的方法,可以在编写一个类,
继承Animal,来替换Dog的操作。
这些留言,似乎并没有解答出楼主在8楼所提出的疑问。我就自不量力,抛砖引玉一下:Animal dog = new Dog();
在很多时候更好一些,比如还有一个Animal的子类Cat,
在后续代码中,如果需要让dog变量引用Cat对象的话,
那么可以直接:dog = new Cat();
因为dog是父类型的,它可以引用子类型的对象。Dog dog = new Dog();
这样声明的话,dog只可以引用Dog对象。我觉得这体现了解耦的思想。
面向接口编程,意义也就在这里。
JAVA运行机制还分编译和运行两个过程是吧?能解释一下这两个过程吗???
JAVA运行机制还分编译和运行两个过程是吧?能解释一下这两个过程吗???
(2)Dog dog=new Dog();
第一个定义对象实现了多态,(1)和(2)中的调用方法其实是一样的,但是多态比较灵活
这样Animal的所有子类都能作为参数,实现了代码的复用,将来扩展时也不需要修改方法。
//其实使用接口和算法族效果更佳。
{
private:
Animal FAnimal;
,,,,,
}对象A调用 FAnimal.XXX 时才显示出多态的威力了. (如果换成IAnimal可能更好)
//你的朋友送给你一个宠物,很显然是个动物,对吧,他和他带来的礼物还在路上,你就迫不及待的想看看是个什么东东
dog.狗刨式游泳();
//然而你还不知道这个动物是什么,你怎么敢说这个动物会狗刨式游泳呢?
//如果你把它扔到你家门口的小池塘子里面,你敢保证你的朋友不会跟你绝交吗?
//所以 dog.狗刨式游泳();在编译的时候会报错,为了程序的安全,不能访问对象不存在的特性Dog dog = new Dog();
//你守在村东口,老远老远你就看到了,你确信就是一只小狗
dog.狗刨式游泳();
//把它扔到你家门口的小池塘子里,它游得可欢实了
//你的朋友送给你一个宠物,很显然是个动物,对吧,他和他带来的礼物还在路上,你就迫不及待的想看看是个什么东东
dog.狗刨式游泳();
//然而你还不知道这个动物是什么,你怎么敢说这个动物会狗刨式游泳呢?
//如果你把它扔到你家门口的小池塘子里面,你敢保证你的朋友不会跟你绝交吗?
//所以 dog.狗刨式游泳();在编译的时候会报错,为了程序的安全,不能访问对象不存在的特性 Dog dog = new Dog();
//你守在村东口,老远老远你就看到了,你确信就是一只小狗
dog.狗刨式游泳();
//把它扔到你家门口的小池塘子里,它游得可欢实
就象String 类重写equals方法一样
A c=new A();
B d=new B();
String a="a";
String b="b";
System.out.println(c.equals(d));//调用的是基类equals方法
System.out.println(a.equals(b));//调用的派生类String类 equals方法
这个答案很有道理,我只简单说一说,
int i = 9;
我们是现声明整型变量int ,名字就i , 定义了一个数字 9 ,从右往左看,将数字9赋予变量iAnimal dog = new Dog(); 左边Animal dog 同上面一样是声明 Animal 这个类的对象 dog
右边 new Dog()是实例化一个对象,这一步有一个调用 Dog 类构造函数初始化这个类的过程,一般就是给这个类的属性赋值;
并且左边这个引用指向右边
Animal dog = new Dog();
Dog dog = new Dog(); 只看右边都是在实例化Dog这个对象,调用构造函数初始化属性
再看左边,前者是声明父类对象,后者是声明子类对象,
前者是一个向上转型,Animal dog 引用指向new Dog();子类对象当成父类对象,只能调用父类的成员,如果子类重写了父类的方法就根据这个引用指向调用子类重写的这个方法(这个方法就是覆盖override)。这个调用过程就称为“动态绑定”。
jvm会制作出一个关于一个方法的详细列表
core java里好像是继承那章节里有个 动态绑定那节 详细的介绍了动态绑定的过程 可以去查阅下
什么是“向上还原”或“向上转型”楼主可查java基础级的书籍,在继承和多态等章节均可找到,或是百度谷歌一下
关于区别楼主可以写两个类,类a有方法A()B(),类B有同名同参同返回值的A()B()和独有的C(),如果楼主采用 Animal dog = new Dog(); 的方式,是无法使用C()的,而Dog dog = new Dog();就完全可以。
Dog 类 继承了 Animal类。
Animal dog = new Dog();
也就是说你可以用Animal 内的方法,丢掉了Dog 类的新方法。
和 Dog dog = new Dog();
你可以用Dog 内的方法,也可以用Animal类内的方法,私有方法除外。
狗继承了动物! 动物 = new 狗; 这里只能调用动物的属性方法,如果狗继承动物后重写了动物里的一些方法,那么就调用狗重写的那个方法.
但是不能调用狗的自己的方法,比如狗欺负猫这个方法,动物没有,只有狗有. 狗 = new 狗; 可以调用狗从动物继承过来的方法,还包括它自己的特性的方法
1、从字面解释:就是向上转型
2、从功能上解释:就是为了JAVA的灵活,解耦,简便(也就是多态)
父类引用对象指向子类。
public Person createFactory(personEnum type){
Person person=null;//如果返回子类对象
switch(type){
case STUDENT:
person=new Student();
break;
case TEACHER:
person=new Teacher();
break;
}
return person;
}
前台
PersonFactory pf=new PersonFactory();
Person person=null;
person=pf.createFactory(personEnum.STUDENT);//子类对象接收会怎样
person.Run();
Animal dog = new Dog();
在这个声明之后可以:Dog d=(Dog)dog;//此时d可以用dog对象的成员了
Posted on 2007-04-11 18:56 天轰穿 阅读(16646) 评论(38) 编辑 收藏 网摘 所属分类: 学习笔记 、VS2005控件演示 、vs2005入门 .net 2.0系列视频
因为这个视频还没有做完,我想把抽象类和接口全部做完,估计是两级或者三级,因为里面包含对以前学过的知识的一个复习和其他一些小细节,所以不做完就很难得到一个完整的思路,这两点确实是很绕的,如果没有一个完整的思路和一个比较有说服力的演示,确实很难说清楚!说实在这两个知识点我确实做得很头疼,演示简单了怎么也说不出为什么需要用这个东西,复杂了又很难讲清楚!我实在很郁闷,目前只是把基本的东西做出来了,完整的演示还没有做出来,我想实在不行就搬一套设计模式来讲出为什么需要用吧.下面是目前已经做了的,我先发布出来,免得跟我一样的急性子门受不了漫长的等待,哈哈,安慰下上一节呢狠狠的废话了一大盘(我好久没有废话得这样过瘾了,哈哈).
从这节我们就深入继承,不在是28级讲的那么简单的手啊眼啊男人女人什么的. 如果没记错的话,我以前应该说过类同时只能继承一个类. 那这话是否是真的呢,我有骗你没有呢??? 哈哈,想知道吗? 继续看后面的教程吧! 提个醒,我这人凡事爱走偏锋,连瞒天过海的事都会做,所以也许我确实骗了你........首先我们给出抽象类和接口的概念,大家可以把视频暂停下来记录一下.抽象类:又叫抽象基类(不是鸡肋):他在定义的时候使用 abstract 关键字标记的一般类.他可包含一般类所包含的所有特性,例如,字段,属性,方法,另外他还包含一个很特殊的方法,叫抽象方法(这些方法基本上是没有执行代码的函数标题,而派生于该类的的类就必须提供执行的代码).最可气的是,他不能被实例化,他主要的用在类的定义和部分实现这方面,所以他需要在扩充类中完整的扩充并实现功能.抽象方法: 当类中的方法在声明的时候加上 abstract 关键字的时候,他就被我们称为抽象方法(洋名字叫 abstract method , 其实偷偷告诉你哈,我最近学了好多英文单词,虽然还是常常读错,但是已经有很大进步了,估计要不了多久就可以在那里大声朗读李白曾经写过的一首英文诗歌了),但是有个很重要的提醒,只有在抽象类和接口中才可以使用抽象方法.例如 : 下面这个public abstract class Thc123_Com
{
public abstract void GoTo();
} public class Thc123_Net : Thc123_Com
{
public override void GoTo()
{
//实现上面抽象方法
}
}=========================================================================================在讲接口之前呢我又想跟大家吹下牛, 大家知道我们的组装计算机,即便是那些品牌机他实际上也是来自很多不同的厂商然后组装起来的, 那么这写硬件之间就有一个必然的联系,那就是他们之间一定要有规范的接口,可是就拿我们的主板来说吧,这个CPU,他既可以是赛阳的,也可以是奔腾的,更可以是速龙,闪龙,当然我跟特别非常十分希望再加上一个咱们中国的CPU品牌,这些CPU肯定采用了一些不同的运算方式啊,所以说我们这个接口就还要学会一点(我们常常劝老人的话,他只要在孝顺你,你就别关他那么多的家务事),说得太好了,我们的接口还要做的事就是不管对方是怎么实现的,反正你插到这里面((*&^#@*&^%$%^$$#$)你就要实现具体的功能,至于你怎么实现就不管那么多了.
接口:他呢其实也是一种特殊的抽象类,用 interface 关键字标记,他的定义没有 class 关键字,他可以包含 方法和属性和事件,但是方法也只能是虚拟方法,任何派生于该接口的类就必须提供执行的代码.任何接口成员前面都不能加修饰符.接口可用的修饰符有 new , public ,protected , internal , private ,但是同一声明中修饰符只能有一个,new关键字只能出现在镶套接口中,表示复写继承来的同名成员.
接口和类一样,可以被继承和发展,但不同的是,类继承不仅说明继承也会实现继承,但是接口继承只是说明继承,通俗的说,派生类可以继承基类的方法实现,而派生接口只是继承父接口的方法说明,却没有继承父接口的实现.语法:
interface Ibook
{
string GetBookName();
}接口相关知识:1.声明在接口中的方法,不可以包含方法的内容区块,简单来说就是不能有大括号存在,例如下面
public interface Ibook
{
string GetBookName()
{ }
}2. 实现接口的类就要这样写 public class Employee:Ibook , IUser
{}3 . 实现接口需要注意的一些东东(1).实现一个接口就必须完成接口里的所有方法.(就好象谁家有几个女儿,有漂亮的有对不起观众的,我要去娶那个漂亮的,然后人家开口了,小伙子,你要娶我女儿可以,但是你必须把几个女儿全部娶了,否则我会让你后悔一辈子. )(2).在实现的类中又有几点必须遵循的(我倒,都三重编号了,看来我写的书后期编辑是件很棘手的事)
•存取权限必须相同 ;
•返回值类型必须相同
•方法的名称必须相同
•参数必须相同(3) . 接口内的方法不能用 virtual 关键字申明,更不要设置存取权限.下面我们继续来看下个例题另外还有一种呢就是以明确的方式实现接口简单来说就是方法前面必须加上接口的名称.这个解释起来没有看起来明确,来吧,看这里(怎么听这话有点怪怪的,难道是我思想不健康,按理说我算是生在阳光下,长在花丛中(不过18岁以后我就基本上是成长在一群 花虫 中了),没理由思想会这么XX啊.)下面针对抽象类和接口做一个详细的对比抽象类( abstract method ) 接口 ( interface )
可以包含实现区块 不能包含实现区块
可以包含抽象方法 不能包含抽象方法
可以包含非public成员 不可以包含非public成员
能继承其他的类,包含非抽象类 能继承其他接口
可以控制版本 无法控制版本
不能被实例化 不能被实例化
virtual: 这个关键字表示当前方法、属性、索引器或事件的抽象实现或虚实现可被任何派生自这个类的扩充类进行复写.
override: 表示当前方法已经改写了基类的同名同参数的方法、属性、索引器或事件的抽象实现或虚实现.
void method(){System.out.println("Base");} //父类的method方法
void test(){method();} //父类的特有test方法
}
public class B extends A{
void method(){System.out.println("Sub");} //重写了父类的方法
public static void main(String[] args) {
A a=new B(); //父类的引用指向子类的对象
a.test(); // 打印 Sub
}
}
void method(){System.out.println("Base");} //父类的method方法
void test(){method();} //父类的特有test方法
}
public class B extends A{
void method(){System.out.println("Sub");} //重写了父类的方法
public static void main(String[] args) {
A a=new B(); //父类的引用指向子类的对象
a.test(); // 打印 Sub
}
}