抽象类和接口
抽象类
- 抽象类出现的原因:在多态中父类方法的方法体是多余的,所以出现了抽象方法,又因为类中含有抽象方法则该类必须为抽象类;
-
abstract
可以修饰类和方法:
1、abstract修饰的类称为做抽象类;
2、abstract修饰的方法叫做抽象方法,抽象方法只有声明部分
,而没有具体的方法体
。
一个abstract类只关心它的子类是否具有某种功能,并不关心其自身功能的具体行为,功能的具体行为由子类负责实现。抽象类的子类必须实现抽象类中的所有抽象方法,否则子类也必须是抽象类。
抽象类不能被直接实例化,即
不能
使用关键字new来创建该抽象类的对象
抽象类中可以没有abstract方法(为了强迫使用者必须通过继承来使用这个类);但是一旦类中包含了abstract方法,则这个“类”一定是abstract类,即有
抽象方法的类一定是抽象类。
- 抽象类中的抽象方法是多态的一种表现形式。
public abstract class Mammal {
//可以有构造方法
public Mammal(int age) {
System.out.println("父类有参构造方法");
}
public void fly() {
System.out.println();
}
public abstract void eat();
public abstract void move();
//用abstract修饰的方法为抽象方法
//当一个类中含有抽象方法时,则该类必须是抽象类
//抽象类中不能包含被static修饰的静态抽象方法
}
----------
public class Whale extends Mammal{
public Whale(int age) {
super(age);
}
//默认调用父类的一个无参构造方法,
//若父类有一个有参的(没有无参构造方法),则必须调用,否则出错
//子类必须调用父类的构造方法
@Override
public void move() {
System.out.println("鲸鱼靠鳍移动。。。。。。");
}
@Override
public void eat() {
System.out.println();
}
}
----------
public class Test {
public static void main(String[] args) {
Mammal mammal = new Whale(12);//Whale whale = new Whale();Mammal mammal=whale;
mammal.move();
//1、在多态中父类中的方法体是多余的;一个类中含有抽象方法时,则该类必须是抽象类
//Mammal mammal = new Mammal();2、此语句错误,因为抽象类不能创建对象,
//但抽象类含有构造方法,仅限于子类调用,这是一个抽象类
//抽象类不关心自身行为特征,只约束自子类(子类必须实现抽象类中的【所有】抽象方法,否则子类为抽象类)
}
}
//输出:
//父类有参构造方法
//鲸鱼靠鳍移动。。。。。。
抽象类与普通类的区别
- 抽象类前面由abstract修饰,而普通类没有。
- 抽象类不能创建对象,普通类可以创建对象。
- 抽象类中可以有抽象方法,普通类中一定没有抽象方法;
总结
- 被abstract修饰的类和方法分别称为抽象类和抽象方法【抽象方法中没有方法体】。
- 抽象类不能通过new关键字创建对象。
- 抽象类中可以有构造方法。
- 抽象类中可以没有abstract方法;但类中如果有抽象方法,此类必须为抽象类。
- 抽象类的子类必须实现抽象类中的所有抽象方法,否则子类必须为抽象类。
- 抽象类中的抽象方法是多态的一种表现形式。
- abstract final class Mammal{ } 能编译通过吗, why?
原因:如果抽象类前面可以添加final就意味着该类无法被继承,
也就意味着该抽象类中的抽象方法永远无法得到实现,
也就意味着抽象类中的抽象方法是无用的。
- Mammal抽象类中move抽象方法的访问权限可以为private吗,即“private abstract void move();”, why?
原因:被private修饰的方法其作用范围为本类,
如果抽象类中的抽象方法被private修饰就意味着该方法永远无法被实现。
- Mammal抽象类中move抽象方法可以由static修饰吗,,即“public static abstract void move();” why?
原因:
抽象类中的抽象方法如果可以被static修饰就意味着可以使用抽象类的类名来使用该方法,
但是该抽象方法没有方法体,不具有使用的价值,
所以Java中规定抽象类中不能包含被static修饰的静态抽象方法。
接口
1、接口
- Java接口是
抽象方法的集合
,其定义语法为:
访问权限控制符 interface 接口名 [extends 接口列表] {
常量;
抽象方法;
内部类;
}
1、该访问控制符只有两个:public和友好的。
2、接口名的命名规则和类名的命名规则相同。
-
接口一般以大写I开头
,后面的类名仍以大写字母开头,例如【IMammal】. - 接口内只能
包含常量(public static final)、抽象方法及内部类
。 - 接口中的抽象方法必须为
public访问权限控制符或友好的
,不能为其它控制符。
public interface IMammal {
public abstract void eat();
public abstract void move();
}
- 通过
extends
关键字可以使自定义的接口实现继承
,但需要注意以下两点:
1、接口只能继承父接口,不能继承抽象类和普通类。
2、接口弥补了Java单一继承的缺点(Java中的类只能继承一个父类),即接口可以继承多个父接口,它们之间用英文逗号隔开。
public class Bat implements IMammal{
@Override//重写标志。右键左边空白,找到Build Path,点击configure Build Path,找到Libraries,Edit将JDK升级到6
//@Override要求JDK6.0或JDK6.0+
public void move() {
System.out.println("蝙蝠靠翼移动。。。。。。");
}
public void eat() {
System.out.println("蝙蝠吃蚊子。。。。。。");
}
}
2、接口实现
- 类通过i
mplements
关键字实现接口,Java中的类只能是单继承,但却可以实现多个接口以弥补Java类单继承的不足,其语法如下:
访问控制符 修饰符 class 类名 implements 接口1 [,接口2, ……] {
变量;
方法;
}
//注意:在类中实现接口时重写的规范。
- 如果一个类实现了一个接口,但没有实现接口中的所有抽象方法,那么这个类必须是
abstract类
。 - 如果多个接口中定义了相同的抽象方法,则在实现类中只实现其中一个即可;
3、接口回调
- 接口回调描述的是一种现象:接口声明的变量指向其实现类实例化的对象,那么该接口变量就可以调用接口中的抽象方法。【多态的另一种称呼】
- 接口没有构造方法,不能创建自己的对象,但是
可以引用实现类的对象。
接口中的抽象方法可以省略public abstract,接口中的抽象方法只能是public级别的
4、 接口实现类
- 接口实现类可以直接使用接口中的常量
接口中变量是静态常量且是public,public static final
比如上式中的PI前面就省略了public static final
- 接口实现类所实现的多个接口中有常量名相同的常量,则在实现类中不能直接使用,必须使用类名来确定到底调用哪个接口中的常量
package com.baidu.abs;
public interface ICircle {
String Name = "圆形";
}
----------
package com.baidu.abs;
public interface ISquare {
String NAME = "方形";
}
----------
package com.baidu.abs;
public class ICss implements ICircle,ISquare{
public static void main(String[] args) {
System.out.println(ICircle.Name);//不能直接写NAME
}
}
5、 默认方法
Java8以前版本中规定,接口中所定义的方法只能是抽象方法。
从Java8开始,接口中可以添加一个或多个由
default
关键字修饰的非抽象方法,该方法又称为扩展方法,该默认方法将由接口实现类创建的对象来调用
public interface IMammal {
void move();
public default void eat() {
System.out.println("哺乳动物正在吃......");
}
}
6、静态方法
- 从Java8开始,接口中可以添加一个或多个由
static
关键字修饰的非抽象方法,该方法将由接口或其实现类
直接调用, -
注意:
接口中的静态方法,实现类无法继承,默认方法实现类可以继承。
代码1:
interface IMammal {
void move();
public static void eat() {
System.out.println("哺乳动物正在吃......");
}
}
class Whale implements IMammal{
@Override
public void move() {
System.out.println("靠鳍移动......");
}
}
class Test{
public static void main(String[] args) {
Whale.eat();
//Whale无法调用IMammal接口中eat静态方法,
//说明Whale【无法】继承接口中【静态方法】
}
}
----------
代码2:
interface IMammal {
void move();
public default void eat() {
System.out.println("哺乳动物正在吃......");
}
}
class Whale implements IMammal{
@Override
public void move() {
System.out.println("靠鳍移动......");
}
}
class Test{
public static void main(String[] args) {
new Whale().eat();
//Whale可以调用IMammal接口中eat默认方法,
//说明Whale可以继承接口中【默认方法】。
}
}
Whale无法调用IMammal接口中eat静态方法,
说明Whale无法继承接口中【静态方法】
7、 函数式接口
- 如果接口内只定义一个抽象方法,则该接口称为函数式接口
@FunctionalInterface
interface IMammal {
String NAME = "哺乳动物";
void move(); //一个抽象方法
public default void eat() {
System.out.println("哺乳动物正在吃......");
}
}
-
注意
- 可以使用@FunctionalInterface 注解来验证一个接口是不是【函数式接口】,Java8中java.lang.Runnable、java.util.Comparator都是函数式接口;
- 函数式接口中可以定义多个常量、多个默认方法和多个静态方法,但只能定义一个抽象方法及多个java.lang.Object中的public方法,
@FunctionalInterface
interface IMammal {
void move();
boolean equals(Object obj);
}
8、 抽象类与接口的区别
总结
-
JDK8.0与JDK8.0+支持一下三个方面:
1、接口中可以定义多个由default关键词修饰的默认方法
2、接口中可以定义一个或多个静态方法
3、如果接口内只定义一个抽象方法,则该接口称为函数式接口 @FunctionalInterface
- 函数式接口中可以有多个抽象方法,但是【除了其中一个外】其他的抽象方法必须是在Object中实现的
- Runnable Comparator 都是函数式接口
- 函数式接口中可以有默认方法【default】
1、接口中的方法全是抽象方法
2、接口中的抽象方法必须通过implements实现
3、接口一般以I开头
4、@Override要求JDK6.0或JDK6.0+
5、接口中的抽象方法可以省略public abstract,接口中的抽象方法只能是public级别的
6、接口中变量是静态常量且是public,public static final
7、接口、抽象类、普通类只能使用public或默认的访问权限修饰
8、接口可以继承多个接口,所继承的多个接口用逗号隔开
9、如果一个“类”没有实现接口中定义的所有抽象方法,则这个类必须是抽象类
10、一个类可以实现多个接口,接口之间用逗号隔开
11、实现接口中抽象方法时,必须遵循重写规范
12、如果多个接口中定义了相同的抽象方法,则在实现类中只实现其中一个即可。
13、接口回调(多态的另一种称呼)
14、接口没有构造方法
15、实现类可以直接使用接口中定义的全局变量
instanceof运算符
- instanceof运算符用于判断该运算符前面引用类型变量指向的对象是否是后面类,或者其子类、接口实现类创建的对象。如果是则返回true,否则返回false,其使用格式如下:
引用类型变量 instanceof (类、抽象类或接口)
- instanceof运算符用于强制类型转换之前检查对象的真实类型以避免类型转换异常,从而提高代码健壮性。
package com.baidu.jiekou;
public class Test {
public static void main(String[] args) {
//1、对象是否是由后面的类创建的,是则true,否则false
System.out.println(new Object() instanceof Object);
System.out.println(new Object() instanceof String);
//2、对象是否是由后面类的子类创建的,是则true,否则false
System.out.println(new String() instanceof Object);
//3、对象是否是由后面接口的实现类创建的,是则true,否则false
System.out.println(new Bat() instanceof IMammal);
}
}
package java.lang;
/*
*String.class
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
----------
package com.baidu.jiekou;
public class Test {
public static void main(String[] args) {
String name = "yuzhou";
//三种形式的对象
Object anObject = new Bat();//执行String中equals中的第一个if,返回false
anObject = "yuzhou";//同理,执行第一个if,返回true
anObject = new String("yuzhou");//执行第二个if,比较完后返回true
boolean result = name.equals(anObject);
System.out.println(result);
Object object = new Bat();
//String str = (String)object;
//com.baidu.jiekou.Bat cannot be cast to java.lang.String
//即指类型转换异常,说明 (anObject instanceof String)功能很强大
}
}