Java中abstract类和abstract方法的相关问题

Java中abstract类和abstract方法的相关问题当知道一个类的子类将不同的实现某个方法时,把该类声明为抽象类很有用,可以共用相同的父类方法,不必再定义。抽象类和抽象方法的关系:含有抽象方法的类一定是抽象类,抽象类里不一定含有抽象方法。抽象类存在的意义是用来被继承的。一个类继承了一个抽象类,必须实现抽象类里面所有的抽象方法,否则,此类也是抽象类。 abstract修饰符用来修饰类和成员方法1:用abstract修饰的类表示抽象类,抽象类位于继承树…

Java中abstract类和abstract方法的相关问题当知道一个类的子类将不同的实现某个方法时,把该类声明为抽象类很有用,可以共用相同的父类方法,不必再定义。

抽象类和抽象方法的关系:含有抽象方法的类一定是抽象类,抽象类里不一定含有抽象方法。

抽象类存在的意义是用来被继承的。
一个类继承了一个抽象类,必须实现抽象类里面所有的抽象方法,否则,此类也是抽象类。 

abstract修饰符用来修饰类和成员方法

1:用abstract修饰的类表示抽象类,抽象类位于继承树的抽象层,
抽象类不能被实例化

2:用abstract修饰的方法表示抽象方法,
抽象方法没有方法体
抽象方法用来描述系统具有什么功能,但不提供具体的实现。 

abstract 规则:

1:抽象类可以没有抽象方法,但是有抽象方法的类必须定义为抽象类,如果一个子类继承一个抽象类,子类没有实现父类的所有抽象方法,那么子类也要定义为抽象类,否则的话编译会出错的。

2:抽象类没有构造方法,也没有抽象静态方法。但是可以有非抽象的构造方法

3:抽象类不能被实例化,但是可以创建一个引用变量,类型是一个抽象类,并让它引用非抽象类的子类的一个实例

4:不能用final 修饰符修饰

 


Q:java里面有抽象类么?和接口的区别是什么?

A:java中有抽象类,用关键字abstract修饰。

以下是我对这个问题的看法。

首先,从语法上讲,抽象类是一个类,根据java的单继承体系。如果它有子类,那么它的子类只能继承它。

java允许实现多个接口。所以一个类可以实现多个接口

抽象类里面可以定义各种类型和访问权限的变量(就像普通类一样),也可以定义各种访问权限的方法(就像普通类一样)。

但是接口不可以。在接口里面定义的方法默认就是public abstract的,变量默认就是public static final的。(不管你有没有加权限控制符,不加,默认就是这些权限;加错了,权限缩小了,那么就会报错)

其次,从意义上讲,如果继承一个抽象类,那么抽象类和它的子类就有父子关系,即有类的层次关系(这关系到类的设计问题)。

接口,在我看来,是一种契约或者协议,是一层提供给另一层的接口(可以想象成OSI各层之间的关系)

在某一层中有多个类协作实现这个层的功能,通过接口暴露出去。但这些类之间会有层次关系(is a,has a)

Q:一个方法加abstract和不加abstract有什么区别?就是说不加有什么关系?加了又会怎样?


A:一方法要是加abstract,那么这个方法就是抽象的,须由子类去实现

抽象方法必须在抽象类当中,也就是说,一个类只要有一个方法是抽象的,那么这个类就必须是抽象类

抽象类里面的方法不一定要抽象的,也可以全都不是抽象的

抽象类不能实例化!

所以可以想到,当你不想让你的类被别人实例化,只想这个类的子类可以实例化,那么只要将这个类声明为abstract的就可以了

(和final的情况蛮相近,当你不想让这个类再有子类化,只要在类的声明前面添加final即可)

不过更多的情况下,我想,还是一个抽象类,他既有部分抽象方法,也有部分具体的方法。

具体的方法是已经定义好的,抽象方法需要由子类去实现。(个人感觉和C++的virtual很相近,不过abstract是纯虚的)

 

那么为什么要有抽象类呢?我说过这关系到你类的设计问题。(当然还有不想被实例化)

譬如经常举的一个例子

abstract class Shape{ 

    public abstract void draw(); 

    public abstract void reDraw(); 



class Triangle extends Shape{ 

    public void draw(){…} 

    public void reDraw(){…} 



class Circle extends Shape{ 

    public void draw(){…} 

    public void reDraw(){…} 



当然你可以这样设计

class Shape{ 

    public void draw(){} 

    public void reDraw(){} 

}

这样设计有2个不妥之处:

1.不符合逻辑。Shape是你针对具体的事物(Triangle,Circle)抽象出来的。它定义的方法应该到子类中去实现

2.在设计的时候就应该认识到,实例化Shape是没有意义的,因为Shape本身只是一种抽象。现在别人如果拿来就可以实例化了,这样的操作方式违背了当初设计的意愿。而且会存在潜在的危险。(当前的实现可能看不出危险)

那么,如果把Shape定义成Interface呢?

当然可以

Interface Shape{ 

    void draw(); 

    void reDraw(); 



class Triangle implements Shape{ 

    public void draw(){…} 

    public void reDraw(){…} 



class Circle implements Shape{ 

    public void draw(){…} 

    public void reDraw(){…} 

}

只不过现在子类Triangle,Circle和Shape之间的关系就不是父子了。

这样设计其实违背了常理,因为在我们的观念中,Triangle和Circle本来就应该是一种Shape

而不应该是他们都遵守一定的操作方式(void draw(),void reDraw())

如何扩展这些设计呢?譬如说为Triangle和Circle添加erase方法?

如果是class Shape这样的设计,很简单,只要

abstract class Shape{ 

    public abstract void draw(); 

    public abstract void reDraw(); 

    public void erase(){ 

        Window window=WindowContainer.getCurrentWindow(); 

        window.clean(); 

    } 

}

Triangle和Circle的代码可以原封不动!

你可能会问,为什么不把erase()设计成为abstract的。你当然可以把erase()设计成abstract的,然后在子类中重写这个方法,提供子类自己的实现。

但是,在现实当中,你可能更赞同是用上面的设计。的确,erase方法只要简单的进行擦除就可以了,不是吗?

这样一来,扩展就变的很容易了。

如果是Interface Shape的设计,那你做的事可就多了

Interface Shape{ 

    void draw(); 

    void reDraw(); 

    void erase(); 



class Triangle implements Shape{ 

    public void draw(){…} 

    public void reDraw(){…} 

    public void erase(){  

        Window window=WindowContainer.getCurrentWindow(); 

        window.clean(); 

    } 



class Circle implements Shape{ 

    public void draw(){…} 

    public void reDraw(){…} 

    public void erase(){ 

        Window window=WindowContainer.getCurrentWindow(); 

        window.clean(); 

    } 

}

所有相关的代码,你都要修改!即便他们都做同样的事情!

这样扩展实在是太麻烦了!

你也许和我想的一样,定义接口本身的目的就是告诉大家,任何实现此接口的类,都有自己的实现方法!

我们定义接口的目的是:你们的实现可以不一样,但是你们暴露的接口一定要一致

可以举java类库当中的一个设计,Thread

如果你要设计一个线程类,该怎么办?

两种方法:

//通过继承Thread类来实现 

class MyThread extends Thread{ 

    public void run(){}//覆盖Thread的run方法 



//通过实现Runnable接口来实现 

class MyThread implements Runnable{ 

    public void run(){}//实现Runnable的run方法,MyThread和YourThread的实现都不一样 



(看过Thread的源代码,你就会发现,其实Thread实现了Runnable)

到此,你应该可以看的出来,为什么要继承Thread和为什么要实现Runnable了

 

另外一个抽象类的使用方法是我最近在C++的项目中学习到的。可能你已经会了

 

package com.pamigo.shp; 

abstract class Shape{ 

    public abstract void draw(); 

    public abstract void reDraw(); 

    public void erase(){ 

        doErase(); 

        Window window=WindowContainer.getCurrentWindow(); 

        window.clean(); 

    } 

    protected abstract void doErase(); 



class Triangle extends Shape{ 

    public void draw(){…} 

    public void reDraw(){…} 

    protected void doErase(){ 

        MusicBox.sing(“Amazing Grace”); 

    } 



class Circle extends Shape{ 

    public void draw(){…} 

    public void reDraw(){…} 

    protected void doErase(){ 

        WindowBox.popUp(“I’ll go!”); 

    } 



package com.pamigo.clnt; 

class User{ 

    public static void main(String[] args){ 

        Shape shp=new Triangle(); 

        shp.draw(); 

        shp.erase(); 

    } 

}

//注意我的权限修饰符

我想表达的意思就是,对外界来说,User只能看到Shape的erase方法。

erase方法必须要做Window的清除工作,但为了给子类提供机会做自己的清除工作,所以设计了

protected abstract void doErase();

因为是protected权限,所以User是看不见的。

不管是Circle还是Triangle,都会有自己的doErase方法。并且他们都会在用户调用shp.erase();时被正确的调用

并且不用关心Window是如何被清除的!

这类似于一种回调函数的方式,你可以这么认为。

==========================================================================

abstract作为修饰符,可以修饰类和方法。

1>.抽象类: 不能手动创建对象(JVM可以创建抽象类的对象),但是可以声明抽象类型的引用.      

public class TestAbstract1{           

 public static void main(String[] args){   

             //Animal a=new Animal();     

            //error                     

            Animal a=null;             

              a=new Dog();       

      }     

  }       

  abstract class Animal{      }     

 class Dog extends Animal{       }    

2>.抽象方法:有方法名的定义,没有实现,(只定义了能做什么,没定义怎么做)    抽象方法的好处是允许方法的定义和实现分开。       

abstract class Animal{      

  public abstract void eat();   

   }       

    抽象类和抽象方法的关系:含有抽象方法的类一定是抽象类,抽象类里不一定含有抽象方法       

    抽象类存在的意义是用来被继承的。一个类继承了一个抽象类,必须实现抽象类里面所有的抽象方法,否则,此类也是抽象类。      

abstract class Animal{    

     public void run(){}         

     public abstract void sleep();     

     public abstract void eat();   

   }       

 class Dog extends Animal{  

       public void sleep(){         

          System.out.println(“Dog sleep.”);    

     }        

     public void eat(){    

          System.out.println(“Dog eat.”);  

       }    

   }       

   abstract class Cat extends Animal{       

      public void eat(){           

        System.out.println(“Cat eat.”);        

 }

       }      

     可以声明父类类型子类对象,利用多态调用抽象方法      

 public class TestAbstract1{       

      public static void main(String[] args){     

           Animal a=null;       

          a=new Dog();      

          a.sleep();      

           a.eat();    

   }   

   }        

     抽象类有构造方法,有父类的,也遵循单继承的规律     

    class E{}    

  abstract class Animal extends E{    

         public Animal(){      

         super();      

   }     

 }    

今天的文章Java中abstract类和abstract方法的相关问题分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/33759.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注