抽象
抽象类
抽象类产生的目的: 通过标记类为抽象类来限制只有父类的子类才能够被初始化即防止类的初始化。
设计好继承结构之后必须要决定哪些类是抽象的,哪些类是具体的。具体的类是可以被初始化为对象的
抽象类的语法结构 abstract class 子类 extends 父类{ }
abstract class SonClass extends FatherClass{
public void room(){
}
}
注意: 如果一个子类称为抽象类,那么就不能放在创建new位置。
抽象类除了被继承过之外是没有用途、没有值、没有目的的
public void go(){
Canine c;//Canine为抽象类,这样做是合法的
c=new Canine();//这样做就不是合法的
}
抽象方法
抽象方法的语法结构: public abstract void 方法名称();//抽象的方法代表此方法一定要被覆盖过,抽象的方法没有实体,必须在具体的类中运行
注意: 如果一个类拥有一个抽象方法那么这个类一定是一个抽象类
一个抽象类中可以有抽象方法也可以有非抽象方法
抽象类的方法没有实体(应该就是没有语句块、方法体的意思吧)
多态的使用
Object
Object的特点:
- Java中的所有类都是从Object这个类中继承出来的。也就是说可以将任何一种类看做如下形式 public class 名称 extends Object{ }
- 许多ArrayList的方法都用到Object这个终极类型。因为每个类都是对象的子类,所以ArrayList可以处理任何子类
- 不是抽象类
- Object只有部分方法可以被覆盖。建议用自己写的类去覆盖hashCode()、equals()、toString()
终极对象的作用
对比两个对象是否等价
语句结构: equals(对象名称)
cat c=new cat();
dog d=new dog();
if(c.equals(d)){
System.out.println("false");
}else{System.out.println("false");}//结果明显是会输出false
告知对象是从何处被初始化的
语句结构: get class()
SonClass b=new SonClass();
System.out.println(b.getClass());//返回的就是SonClass
列出对象的哈希代码
语句结构: hashCode()
SonClass b=new SonClass();
System.out.println(b.hashCode());//返回结果是5383406,可以看成唯一ID
由object类型的对象转换为普通类型的对象
Dog d=(Dog)x.getObject(aDog);//把object类型的getObject()转换Dog类型的
列出类的名称和一个随便的数字
SonClass b=new SonClass();
System.out.println(b.(toString));//其结果是SonClass@5224ee,貌似不管怎么变这个@是存在的
ArrayList< DotCom>的意思
限制类型,表明此ArrayList受限且只能保存DotCom的对象
未完待续
给我一杯酒,再给我一支烟——《我还年轻,我还年轻》
ArrayList< Dog>,则次ArrayList受限只能保存Dog的对象
使用Object类型的多态引用付出的代价
当把对象装进ArrayList< Dog>时
两段代码的比较
ArrayList<Dog> myDogArrayList=new ArrayList<Dog>();//保存Dog的ArrayList
Dog aDog=new Dog();//新建一个Dog
myDogArrayList.add(aDog);//把aDog装入ArrayList 中
Dog d=myDogArrayList.get(0);//将Dog值赋给新的Dog引用变量
ArrayList<Object> myDogArrayList=new ArrayList<Object>();//保存对象的ArrayList
Dog aDog=new Dog();//新建一个Dog
myDogArrayList.add(aDog);//把aDog装入ArrayList 中
Dog d=myDogArrayList.get(0);//会出现无法编译的情况,对ArrayList<Object>调用get()方法会返回Object类型,编译器无法确认它是Dog
任何从ArrayList< Object>取出的东西都会被当做Object类型的引用而不管它原来是什么
从ArrayList< Object>取出的Object都会被当做是Object这个类的实例。编译器无法将此对象识别为Object以外的事物
又两段代码的比较
public void go(){//这是一个名为go的方法
Dog aDog=new Dog(); //建立一个名为aDog的Dog类型的对象
Dog sameDog=getObject(aDog);//定义名为sameDog类型为Dog的变量,为其赋值是getObject方法并为方法赋值aDog,而aDog是Dog类型,sameDog也是Dog类型,getObject这个方法及其形参都是Object的,所以会出现错误
}
public Object getObject(Object o){ //这是一个名为getObject的Object类型的对象,并定义了一个名为o、object类型的形参
return o;//因为形参的存在所以要返回变量}
public void go(){
Dog aDog=new Dog();
Object sameDog=getObject(aDog);//此时sameDog是Object类型的所以能够正常运行,它被赋予的值无论是方法本是还是方法中的形参都是Object类型的
}
public Object getObject(Object o){
return o;
}
用Object来调用Object以外的方法(应该就是自定义的方法)
Object o=a1.get(index);
int i=o.hashCode();//Object中本来就有hashCode()这种方法,所以可以正常运行
o.bark();//object没有bark()方法,所以无法正常调用
编译器可以根据引用类型来判断有哪些method可以调用,而不是object的确实类型
Object是一个小范围,而自定义(Snowboard)的是一个大范围,Object不可以调用Snowboard。二者是包含关系(Snowboard包含Object)
由Object转换回去
Object o=a1.get(index);
Dog d=(Dog)o;//将类型转换为Dog
d.roam();//调用非Object类型方法
检查是不是Object类型代码
if(o instanceof Dog){
Dog d=(Dog) o;//如果仍为Object类型就会在执行期间遇到ClassCastExpection异常并终止
}
接口的使用
在程序中,可以重用某个类的方法
把某一方法添加到父类中,那么它的所有子类都会拥有这个父类中的方法
优点: 不需要改变子类程序代码,新增加的子类也能获得相同的方法
缺点: 子类不需要父类的方法被强行赋予
在第一种方法的基础上,把父类的方法设置为抽象的,强迫每个子类覆盖他们
覆盖应该是在七中有详解
优点: 这样所有的子类就可以选择自己要使用的方法,或者什么方法都不使用
缺点: 所有要用到父类方法的子类都要自定义一下,太浪费时间;会让父类的定义变得有局限性,反而让其他类型的程序更难以重复利用
把方法加到有需要的地方
优点: 各个子类没啥关系体样式
缺点: 失去了父类的同一控制;多态将无法起作用;针对各个子类设计程序
接口(Interface。以上三种方法各有缺点,所以使用接口)
我手边这个砖头厚的书味道好香啊,可能是时间的沉淀吧……一定不是因为我妈在外头包饺子
多重继承
是有多个父类的意思,但是Java不支持。多重继承会有“致命方块”的问题。会产生糟糕的复杂性问题。接口可以用来解决多重继承问题却又不会产生“致命”方块这种问题
“致命”方块: 两个子类,两个父类。两个子类继承自父类1,两个子类并进行类覆盖(也就是修改了方法),那么父类2就会很茫然。 为什么不能画流程图呢?
接口(Interface)原理
把全部“父类2”的方法设为抽象的
所有接口的方法都是抽象的,所以任何“父类2”的子类都必须要实现这些的方法
学习已经很累了,妈妈还想让我学做饭。为什么没有表情包,哭唧唧的那种!
接口(Interface)的定义与实现
接口定义: public interface Pet{ 语句块}//使用interface代替class
接口操作: 右击src—new—Interface—输入名称
接口实现: public class 子类名称 extends 父类名称 implements Pet{ 语句块}
Example
public class PracticeFatherClass0 {//父类1
void bark() {
System.out.println("Woof!");
}
void eat(){
System.out.println("Hunger!");
}
}
public interface PracticeFatherClass {//父类2
public abstract void beFriendly();
public abstract void play();
}
public class PracticeNormalClass01 extends PracticeFatherClass0 implements PracticeFatherClass{//子类
public void beFriendly(){
System.out.println("Smile!");
}//普通覆盖
public void play(){
System.out.println("football");
}//必须在子类实现父类2的方法,这是规定
public void eat(){
System.out.println("Hungry!");
}
}
不同继承树的类也可以实现相同的接口
当把一个类作为多态类型运转运用时,相同的类型必须来自同一继承树而且必须是该多态类型的子类;但是当用接口来作为多态类型时,对象就可以来自任何地方,唯一的条件就是该对象必须是来自有实现此接口的类
是不是累了?!放一张即使生气也能美哭我的Phoebe,真的随便截,还没有暂停
类实现多个接口
实现语句
public class Dog extends Animal implements Pet,Saveable,paintable{语句块}
注意:extend只能有一个,而implements后面可以跟 好多个
设计类、子类、抽象类或接口的使用条件
如果新的类无法对其他的类通过IS-A测试时,就设计不继承其他类的类,即普通类
只有在需要某类的特殊化版本时,以覆盖或增加新的方法来继承现有的类,即父类和子类
需要定义一群子类的模板,又不想让程序员初始化此模板时,设计出抽象的类,即抽象类
如果想要定义出类可以扮演的角色,使用接口
调用父类的方法
子类不打算完全覆盖父类的方法,只是要加入额外的动作,使用语句:super.父类方法名称();
abstract class PracticeFatherClass1 {//这是父类
void runReport(){
System.out.println("报告");
}
void printReport(){
System.out.println("输出");
}
}
class PracticeSonClass1 extends PracticeFatherClass1{//这是想修改抽象父类的子类
void runReport(){
super.runReport();//调用父版的方法
System.out.println("子类中修改");
}
}
public class PracticeTestClass1 {//这是测试类
public static void main(String[]args){
PracticeSonClass1 test=new PracticeSonClass1();
test.runReport();
}
}
这是结果:
一个例子
interface ExerciseFather1Class {//带接口父类,方法没有语句块
public int iMethod();
}
abstract class ExerciseRealize1Class implements ExerciseFather1Class{
public int iMethod(){//接口父类的实现,赋予具体语句块
return 7;
}
}
public class ExerciseSon1Class extends ExerciseRealize1Class {//没有任何覆盖的子类
}
class ExerciseSon2Class extends ExerciseRealize1Class {
public int iMethod(){//修改了方法的子类
return 5;
}
}
public class ExerciseSon3Class extends ExerciseRealize1Class {
public static void main(String[]args){//测试类
ExerciseFather1Class []i=new ExerciseFather1Class[3];//只能定义接口父类或者子类的类型,实现接口方法类的类型不可以,即第一个
i[0]=new ExerciseSon2Class();//不能是接口父类,而实现方法类则可以
i[1]=new ExerciseSon1Class();
i[2]=new ExerciseSon3Class();
for(int x=0;x<3;x++){
System.out.println(i[x].iMethod()+" "+i[x].getClass());
}
}
}