[关闭]
@w460461339 2016-11-16T07:02:30.000000Z 字数 4635 阅读 869

Java学习Day2(多态 抽象及接口 内部类)

Java基础


这次学习的内容主要是两个,多态以及抽象和接口。另外还对两个程序作了详细的解读。只是光知道这些理论还是不够,需要知道它们各自的应用场合,并加以练习才行。另外,表格中还提到有设计模式,这个也是需要不断补充的。另外,需要很好的区分变量和对象的不同。变量为紧紧跟在类型后面的那个东西,名称由用户定义。在八大基本类型以及对应的包装类型中,变量即为对象的拥有者,举一个不恰当的例子:

  1. int i;//定义了变量
  2. i=10;//变量i中含有整型对象10;

而在类或者数组中,变量是对象的拥有者。对象是被new出来的。

  1. String s;//声明了一个变量
  2. s=new String("Hello")//定义了字符串对象“Hello”,并让s管理。

1、多态

多态主要是由于子类和父类所引起的。通俗的来说,一个父类的变量可以管理一个子类的对象,这就叫做多态。表现形式为变量的静态类型与其实际管理的对象的动态类型不同:

  1. public class Item{
  2. }
  3. class DVD extends Item{
  4. }
  5. public static void main(String args[]){
  6. DVD dvd=new DVD();//创建了一个DVD类的对象。
  7. Item item=dvd//将DVD类的对象赋给了Item类的变量
  8. //此时,item的静态类型为Item,动态类型为DVD
  9. }

理解多态,首先需要牢记,利用类去声明变量的时候,变量仅仅是对象的管理者,而非所有者。所以,多态可以理解为,具有最高管理权限的父类,可以管理所有子类的对象
不过需要注意的是,当将子类的对象赋给父类的变量的时候,该对象的类型并没有从子类变为父类

  1. public class Item{
  2. }
  3. class DVD extends Item{
  4. }
  5. public static void main(String args[]){
  6. DVD dvd=new DVD();//创建了一个DVD类的对象。
  7. Item item=dvd//将DVD类的对象赋给了Item类的变量
  8. //item管理的是dvd类型的对象
  9. }

将子类对象赋给父类的变量,这样的过程叫做向上造型,向上造型总是安全的(因为子类中一定包含有所有父类的变量)。
另外,虽然item中实际管理的是dvd类,但是不能直接用它去给dvd类的变量赋值,需要通过向下造型。向下造型,目前个人感觉,更多的用在子类对父类方法覆盖的时候或者利用接口的时候。注意,向下造型并不总是安全的,必须保证父类变量管理的对象就是那个需要被赋值的子类变量的类型。

  1. public class Item{
  2. }
  3. class DVD extends Item{
  4. }
  5. public static void main(String args[]){
  6. DVD dvd=new DVD();//创建了一个DVD类的对象。
  7. Item item=dvd;//将DVD类的对象赋给了Item类的变量
  8. //此时,item的静态类型为Item,动态类型为DVD
  9. DVD cvc=item;//error,不能这么干
  10. DVD cvc=(DVDitem;//可以这么干,但必须保证item管理的就是DVD类型的对象。
  11. }

利用多态,可以引出Java中的一种设计方法,即为模版设计方法(也叫作回调,call back)。即为对于一个某一个方法,将参数列表定义为某一种类的顶层父类,这样任何其子类都可以认为是该函数的参数被使用。若是想调用子类自己特殊的方法或者类,在自己的类中实现覆盖即可。
解决的问题:当功能内部一部分实现时确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。

  1. class DVD extends Item{
  2. }
  3. public static void test(Item item){
  4. item.print();//根据传入对象的不同,调用不同子类覆盖的print。
  5. }

当想要知道变量管理的到底是哪个子类,可以用instanceof关键字,(变量名称 instanceof 类型名称),返回值是一个boolean

  1. class DVD extends Item{
  2. }
  3. public static void main(String args[]){
  4. Item i =new DVD();
  5. if(i instanceof DVD){//由于i此时管理的是DVD类型变量,故此处为ture
  6. System.out.println("DVD");
  7. }else{
  8. System.out.println("Item");
  9. }
  10. }

多态完全总结(记着在对象里面把变量叫引用)(除了八大基本类型外所有的变量都是引用类型的变量,所以直接叫引用了):

一、使用父类类型的引用指向子类的对象;
二、该引用只能调用父类中定义的方法和变量;
三、如果子类中重写了父类中的一个方法,那么在调用这个方法的时候,将会调用子类中的这个方法;(动态连接、动态调用)
四、变量不能被重写(覆盖),”重写“的概念只针对方法,如果在子类中”重写“了父类中的变量,那么在编译时会报错。

2、抽象和接口

这个说的完整点,其实是抽象类和接口类。两者都是一种类型,而且关系是这样的(类(抽象类(接口类))),即接口类是特殊的抽象类,抽象类是一种特殊的类。有一点很重要,虽然抽象类以及接口不能定义对象,但它可以用来声明变量

  1. public class abstract Item{
  2. }
  3. interface Cell{
  4. }
  5. public static void main(string args[]){
  6. Item item=new item();//error,不能用来定义对象。
  7. Item item=dvd//dvd是item的子类,没问题。
  8. Cell c=fox//fox实现了接口Cell,也没问题。
  9. }
2.1抽象类

抽象类是一个类,所以它与一般类差别不大,关键字是abstract,加在类的访问属性和class之间,或者加在方法的访问属性和返回值之间。所不同的是,抽象类中一定含有抽象方法,含有抽象方法的也一定是抽象类;而且抽象类不能实例化。并且,继承了抽象类的子类必须实现其所有的方法(或者理解为覆盖也行),不然自己也是一个抽象类(还有,没有抽象变量):

  1. public abstract class Item{
  2. private int number//抽象类中可以存在一般成员变量。
  3. public abstrac void print();//注意,抽象方法是没有方法体的,结尾也要加分号。
  4. public void name(){
  5. }//抽象类中是可以存在非抽象方法的。
  6. }
  7. class DVD extends Item{
  8. public void print(){
  9. System.out.println();//将抽象父类中的抽象方法实现
  10. }
  11. }

需要注意的是,抽象类是不能用来定义对象的。这个从语意上就很好理解,比如Shape是抽象类,它有Circle,Rectangle两个子类。我们可以定义Circle以及Rectangle的对象,但是我们说,我们要一个Shape的对象,就很荒谬了。

2.2接口

接口它是一种特殊的抽象类,利用关键字interface来定义接口,并且不能实例化。接口是纯的抽象类,这里纯是指,它只能含有抽象方法(非静态),成员变量也必须为public static final(公有静态常量):

  1. public interface Cell{
  2. public static final int number=10;//只能存在public static final类型的成员变量,并且必须进行定义初始化。
  3. public abstract void print();//只能存在抽象方法
  4. }

需要注意,接口的中的抽象方法的访问属性只能是public或者不写(感觉不写它也会默认为public,这与一般的类会默认为friendly不同,理由等下说明)。而在子类中,与普通类的覆盖一样,若要实现接口的方法,其访问属性不能降低。而我尝试了几次之后,发现只能将子类中实现的接口方法定义为public,所以说接口中默认的访问属性也应该是public(对方法和变量都一样)

  1. public interface Cell{
  2. //关键字interface与class一样,任何能够出现class的地方都能出现interface。
  3. public static final int number=10;//不写那个public static final也可以,它会默认为public static final的。
  4. public abstract void print();//不写public abstract也没问题,它也会默认为public abstract的。
  5. }
  6. class Fox implements Cell{//类似于extends,表示实现接口
  7. public void print(){//将接口中的方法实现
  8. }
  9. }

可以认为接口是让实现了它的类披上了它的外衣,从而让需要接口类型的操作可以操作这些对象。或者,可以将它理解为特殊的抽象父类,只是一般的抽象父类和子类见会有语意上的联系,而接口和实现了它的类之间,只是有这么一个程序上的关系而已。

一个类可以实现很多接口,但只能继承一个类:

  1. public class Fox extends Animal implements Cell,Creture{
  2. }

接口只能继承接口,不能继承类,也不能实现接口:

  1. public interface Cell extends Creture{//Cell和Creture都是接口。
  2. }

3、内部类

简而言之,就是类的内部还有一个类。通常用在当A类需要直接访问B类中的成员,而B类又需要建立A类的对象,此时将A定义为B类的内部类,而B类称为外部类。内部类可以访问外部类的对象。创建内部类的方法:

外部类名.内部类名 变量名=new 外部类名().new 内部类名();
(相当于创建了外部类对象后,再创建内部类对象)
  1. class Item{
  2. class DVD{
  3. }
  4. }
  5. public static void main(String args[]){
  6. Item.DVD dvd=new Item().new DVD();
  7. }

其实内部类和外部类的成员方法是一样一样的。比如,static的方法和内部类都只能调用外部类的static的成员变量以及成员方法;而存在了static变量的方法和内部类都必须被声明为static的。而对于static的内部类,它就不属于任何一个外部类的对象,而是属于整个外部类了。类比于static的方法,它的调用为:

外部类名.内部类名 变量名=new 外部类名.内部类名();
(类似与通过外部类名去调用它)
  1. class Item{
  2. static class DVD{
  3. }
  4. }
  5. public static void main(String args[]){
  6. Item.DVD dvd=new Item.new DVD();
  7. }

然而,,为了封装,一般不会外部类的外部调用内部类,故会将内部类的访问属性定义为private。

匿名内部类,就是内部类的简写,但有前提,即,必须继承或者实现一个外部类或者接口。换句换说,它就是一个匿名的子类对象。格式:new 父类or接口(){子类内容}

  1. abstract class Demo{
  2. abstract void show();
  3. }
  4. class Outer{
  5. int number=4;
  6. public void method(){
  7. new Demo(){ //实现了接口
  8. void show(){
  9. System.our.println("lala");
  10. }
  11. }.show();//调用了匿名内部类中的函数。
  12. }
  13. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注