抽象类和抽象方法
- 定义:对继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计的非常抽象,以至于他没有具体的实例,这样的类叫做抽象类。
- 关键字:
abstract
abstract
可以修饰:类(抽象类)和方法(抽象方法)
抽象类
- 抽象类不可以实例化
- 抽象类中一定有构造器,便于子类实例化时调用
- 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作。
抽象方法
- 抽象方法没有方法体
- 包含抽象方法的类一定是抽象类,反之抽象类可以没有抽象方法,
- 若子类重写了父类中所有的抽象方法后,此子类是可以实例化
- 若子类没有重写了父类中所有的抽象方法,此子类一定是抽象类,需要使用abstract修饰
举例
abstract class Ani {
public abstract void height();
}
abstract class Person extends Ani {
String name;
int age;
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public void eat() {
System.out.println("人吃饭");
}
// 这不是抽象方法
// public void walk() {
// }
// 抽象方法
public abstract void walk();
}
class Student extends Person {
public Student(String name, int age) {
super(name, age);
}
public void eat() {
System.out.println("学生多吃有营养的饭");
}
public void walk() {
}
@Override
public void height() {
}
}
abstract注意点
- 不能用来修饰属性、构造器、代码块等结构
- 不能用来修饰私有方法(private是不能被重写的,陷入死循环)、静态方法(静态方法不能被重写)、final的方法(不能被重写)、final的类(不能被继承)。
抽象类的匿名子类
匿名子类的非匿名对象
public static void method1(Person p) {
p.height();
p.walk();
}
main:
// 匿名子类的非匿名对象
Person p = new Person() {
@Override
public void walk() {
System.out.println("匿名子类的非匿名对象walk()");
}
@Override
public void height() {
System.out.println("匿名子类的非匿名对象height()");
}
};
method1(p);
匿名子类的匿名对象
// 匿名子类的匿名对象
method1(new Person() {
@Override
public void height() {
System.out.println("匿名子类的匿名对象height()");
}
@Override
public void walk() {
System.out.println("匿名子类的匿名对象walk()");
}
});
抽象类应用:模版方法设计模式(TemplateMethod)
- 抽象类作为多个子类的通用模版,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
- 解决问题:当功能内部一部分实现是确定的,一部分实现是不确定的。这是可以把不确定的部分暴露出去,让子类去实现。
- 应用:
- 数据库访问的封装
- Junit单元测试
- Servlet关于doget/dopost方法
- Spring中JDBCTemlate等
public class TeamlateTest {
public static void main(String[] args) {
SubTemplate sub = new SubTemplate();
long codingTime = sub.codingTime();
System.out.println("代码执行时间:" + codingTime);
}
}
//模版
abstract class Template {
// 计算代码的执行时间
public long codingTime() {
long start = System.currentTimeMillis();
code();
return System.currentTimeMillis() - start;
}
public abstract void code();
}
//不确定的部分进行子类的重写
class SubTemplate extends Template {
@Override
public void code() {
// 求质数
for (int i = 1; i <= 1000000; i++) {
boolean bool = true;
for (int j = 2; j < Math.sqrt(i) ; j++) {
if (i % j == 0) {
bool = false;
break;
}
}
if (bool) {
System.out.println("1000以内的质数:" + i);
}
}
}
}
接口(interface)
- 有时必须从几个类中派生出一个子类,继承他们所有的属性和方法,但是Java不支持多重继承;有了接口,就可以实现多重继承的效果。
- 接口就是规范,定义了一组规则。
- 继承是是不是的关系,接口实现的是能不能的关系。
- 接口的本质是契约、标准、规范,定制好以后大家都要遵守。
说明
- Java中,接口和类是并列的两个结构
- 如何定义接口:定义接口中的成员:
- JDK7及以前:只能定义全局常量和抽象方法
- 全局常量:public static final的.但是书写时,可以省略不写
- 抽象方法:public abstract的
- JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法
- JDK7及以前:只能定义全局常量和抽象方法
- 接口中不能定义构造器的!意味着接口不可以实例化。
- Java开发中,接口通过让类去实现(implements)的方式来使用:
- 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
- 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
- Java类可以实现多个接口 --->弥补了Java单继承性的局限性
- 格式:
class AA extends BB implements CC,DD,EE
- 格式:
- 接口与接口之间可以继承,而且可以多继承
实现
public class InterFaceTest {
public static void main(String[] args) {
Birg b = new Birg();
b.flyMethod();
b.stop();
}
}
interface Flyable {
// 常量
public static final int MAX_SPEED = 7900;
int MIN_SPEED = 1;// 默认省略掉了public static final
// 抽象方法
public abstract void flyMethod();
// 接口不能有构造器,也就说明接口不能被实例化
// Interfaces cannot have constructors
// public Flyable() {
//
// }
void stop();// 默认省略了public abstract
}
//如果实现类覆盖了接口中的所有抽象方法,则此类可以实例化
class Birg implements Flyable {
@Override
public void flyMethod() {
System.out.println("用翅膀飞");
}
@Override
public void stop() {
System.out.println("缓慢落地");
}
}
//如果实现类没有覆盖接口中的所有抽象方法,则此类不可以被实例化,是一个抽象类
abstract class Birg2 implements Flyable {
@Override
public void flyMethod() {
}
}
//*************************
//接口之间可以多继承
interface AA {
}
interface BB {
}
class CC implements AA, BB {
}
//类可以单继承多实现
class EE {
}
class DD
extend EE implements AA,BB
{
}
接口多态性
public class InterFaceTest2 {
public static void main(String[] args) {
Phone phone = new Phone();
stransData(phone);
}
//接口的多态性
private static void stransData(USB usb) {
usb.start();
usb.stop();
}
}
//USB接口协议规范
interface USB {
// 速率
public static final int MAX_SPEED = 200;
// 启动
public abstract void start();
// 停止
public abstract void stop();
}
//手机连接规范
class Phone implements USB {
@Override
public void start() {
System.out.println("手机连接USB,开始工作");
}
@Override
public void stop() {
System.out.println("手机连接USB,工作结束,退出");
}
}
//打印机连接规范
class Printer implements USB {
@Override
public void start() {
System.out.println("打印机连接USB,开始工作");
}
@Override
public void stop() {
System.out.println("打印机连接USB,工作结束,退出");
}
}
接口的匿名实现类
创建接口的匿名类的非匿名对象
// 创建接口的匿名类的非匿名对象
USB mp3 = new USB() {
@Override
public void start() {
System.out.println("MP3连接USB,开始工作");
}
@Override
public void stop() {
System.out.println("MP3连接USB,工作结束,退出");
}
};
stransData(mp3);
}
创建接口的匿名类的匿名对象
//创建接口的匿名类的匿名对象
stransData(new USB() {
@Override
public void start() {
System.out.println("U盘连接USB,开始工作");
}
@Override
public void stop() {
System.out.println("U盘连接USB,工作结束,退出");
}
});
面试题:抽象类和接口有哪些异同?
接口的应用(目前了解即可)
代理模式
- 代理设计就是为其他对象提供一种代理以控制对这个对象的访问。
- 应用:
- 安全代理
- 远程代理
- 延迟加载
public class StarTest {
public static void main(String[] args) {
Broker broker = new Broker(new Songer());
broker.interView();
broker.signUp();
broker.song();
}
}
interface Star {
// 面谈
public abstract void interView();
// 签约
public abstract void signUp();
// 唱歌
public abstract void song();
}
//被代理类:歌手
class Songer implements Star {
@Override
public void interView() {
}
@Override
public void signUp() {
}
@Override
public void song() {
System.out.println("明星:唱歌~~~~");
}
}
//代理类:经纪人
class Broker implements Star {
private Star star;
public Broker(Star star) {
super();
this.star = star;
}
@Override
public void interView() {
System.out.println("经纪人面谈");
}
@Override
public void signUp() {
// 经纪人签约
check();
System.out.println("经纪人签约");
}
private void check() {
System.out.println("经纪人检查合同");
}
@Override
public void song() {
// 经纪人让歌手唱歌
star.song();
}
}
工厂模式
笔试题
排错:笔试1
public class IntreFaceOne extends MB implements MA {
public static void main(String[] args) {
new InterFaceOne().pX();
}
public void pX() {
System.out.println(x);
}
}
interface MA {
int x = 10;
}
class MB {
int x = 20;
}
答案是错误
System.out.println(x);//报错The field x is ambiguous,x属性是不确定的
因为MA和MB中的属性名一样
如果调用MA中的x:MA.x
调用MB中的x:super.x
修改成正确的:
System.out.println(super.x);
System.out.println(MA.x);
排错:笔试2
public class InterFaceTwo implements VC {
@Override
public void play() {
System.out.println("play执行");
}
public static void main(String[] args) {
face = new InterFaceTwo();
face.play();
}
}
interface VA {
void play();
}
interface VB {
void play();
}
interface VC extends VA, VB {
InterFaceTwo face = new InterFaceTwo();
}
答案是错误
interface VC extends VA, VB {
InterFaceTwo face = new InterFaceTwo();
}
face省略了public static final
所以face是常量
不能再main方法中face = new InterFaceTwo();重新创建The final field VC.face cannot be assigned
接口练习(PPT)
Java8中接口新特性
除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法。
格式
- 静态方法:
public static void method(){方法体}
,其中public
是可以省略的,省略后还是public
属性的方法。 - 默认方法:
public default void method(){方法体}
,其中public
是可以省略的,省略后还是public
属性的方法。
public interface CompareA {
// 静态方法,public是可以省略的。
public static void method1() {
System.out.println("CompareA:method1()");
}
//省略后还是public修饰的
static void method2() {
System.out.println("CompareA:method2()");
}
// 默认方法,public是可以省略的。
public default void method3() {
System.out.println("CompareA:method3()");
}
//省略后还是public修饰的
default void method4() {
System.out.println("CompareA:method4()");
}
}
静态方法的调用
- 接口中定义的静态方法,只能通过接口来调用
public class SubClassTest {
public static void main(String[] args) {
SubClass c = new SubClass();
// 知识点1: 接口中定义的静态方法,只能通过接口来调用
// The method method1() is undefined for the type SubClass
// c.method1();
CompareA.method1();
CompareA.method2();
}
}
class SubClass implements CompareA {
}
默认方法的调用
- 实现类对象可以调用接口的默认方法
- 如果实现类重写了接口中的默认方法,则调用的是重写的方法
public class SubClassTest {
public static void main(String[] args) {
SubClass c = new SubClass();
//知识点2:实现类对象可以调用接口的默认方法
//如果实现类重写了接口中的默认方法,则调用的是重写的方法
c.method3();
c.method4();
}
}
class SubClass implements CompareA {
@Override
public void method4() {
System.out.println("SubClass:method4()");
}
}
父类和接口出现同名同参数的方法
- 如果子类(实现类)继承的父类和实现的接口中声明了同名同参数的默认方法,则会调用父类中的同名同参数的默认方法 --->类优先原则
public class SuperClass {
public void method3() {
System.out.println("SupserClass:method3()");
}
}
public class SubClassTest {
public static void main(String[] args) {
SubClass c = new SubClass();
//知识点3:如果子类(实现类)继承的父类和实现的接口中声明了
//同名同参数的默认方法,则会调用父类中的同名同参数的
//默认方法 --->类优先原则
c.method3();
}
}
class SubClass extends SuperClass implements CompareA {
@Override
public void method4() {
System.out.println("SubClass:method4()");
}
}
接口多实现中出现同名同参数的默认方法
- 实现类中出现了多接口,而这个多接口中定义了同名同参数的默认方法,在实现类中没有重写此方法的情况下,报错---> 接口冲突。
public interface CompareB {
public default void method3() {
System.out.println("CompareB:method3()");
}
}
//Duplicate default methods named method3 with the parameters () and () are inherited from the types CompareB and CompareA
class SubClass implements CompareA, CompareB {
@Override
public void method4() {
System.out.println("SubClass:method4()");
}
}
- 解决方式:实现类重写同名同参数的方法。
class SubClass implements CompareA, CompareB {
@Override
public void method3() {
}
}
实现类(子类)中调用父类或接口的(默认)方法
- 调用父类中的方法:
super.方法
- 调用接口中的默认方法:
接口名.super.方法
class SubClass extends SuperClass implements CompareA {
@Override
public void method4() {
System.out.println("SubClass:method4()");
}
public void my() {
//调用父类的方法
super.method3();
//调用CompareA中的默认方法
CompareA.super.method3();
CompareA.super.method4();
}
}
内部类
- Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类
- 分类:
- 成员内部类:与属性同一级别。(静态、非静态)
- 局部内部类:构造器、方法、代码块。
成员内部类
- 分类:
- 静态成员内部类
- 非静态成员内部类
- 作为外部类的成员:
- 调用外部类的结构
- 可以被static修饰
- 可以被4种不同的权限修饰
- 作为一个类:
- 类内可以定义属性、方法、构造器等
- 可以被final修饰,表示此类不能被继承。言外之意,不使用final,就可以被继承
- 可以被abstract修饰
public class InnerClassTest {
}
class Person {
String name;
int age;
// 静态成员内部类
static class Dog {
}
//可以被4中权限修饰符修饰
private class A{}
protected class B{}
// 非静态成员内部类
class Brid {
public String getPersonName() {
// 调用外部类的结构-方法
method2();
// 调用外部类的结构-属性
return name;
}
}
public void method1() {
// 方法中定义局部内部类
class AA {
}
}
public Person() {
// 构造器中定义局部内部类
class CC {
}
}
{
// 代码块中定义局部内部类
class BB {
}
}
public void method2() {
System.out.println("method2");
}
}
局部内部类
class InnerClass {
public void method1() {
// 方法中定义局部内部类
class AA {
}
}
public InnerClass() {
// 构造器中定义局部内部类
class CC {
}
}
{
// 代码块中定义局部内部类
class BB {
}
}
}
内部类关注的问题
如何实例化成员内部类的对象
- 实例化非静态成员内部类:
外部类 外部类名 = new 外部类();
外部类.内部类 内部类名 = 外部类名.new 内部类();
- 实例化静态成员内部类:
外部类.内部类 内部类名 = new 外部类.内部类();
接InnerClassTest
代码
//实例化非静态成员内部类
Person p = new Person();
Person.Brid brid = p.new Brid();
//实例化静态成员内部类
Person.Dog dog = new Person.Dog();
如何在成员内部类中区分调用外部类的结构
- 静态成员内部类中只可以调用外部类静态的结构。
- 非静态成员内部类可以调用外部类静态、非静态的结构
- 如果外部类属性、内部类属性、内部类方法形参名称一样,调用方法如下:
class User{
int age;
class UserData{
int age;
public void setAge(int age) {
//调用形参
System.out.println(age);
//调用内部类属性
System.out.println(this.age);
//调用外部类属性
System.out.println(User.this.age);
}
}
}
开发中局部内部类的使用
public class InnerClassTest1 {
//开发中很少见
public void method(){
//局部内部类
class AA{
}
}
//返回一个实现了Comparable接口的类的对象
public Comparable getComparable(){
//创建一个实现了Comparable接口的类:局部内部类
//方式一:
// class MyComparable implements Comparable{
//
// @Override
// public int compareTo(Object o) {
// return 0;
// }
//
// }
//
// return new MyComparable();
//方式二:
return new Comparable(){
@Override
public int compareTo(Object o) {
return 0;
}
};
}
}
Day15问题
- abstract能修饰哪些结构?修饰后,有什么特点?
- 类:不能实例化,需要通过子类继承,进行子类的实例化。
- 方法:没有方法体,需要子类继承覆盖方法;抽象方法所在的类一定是抽象类。
- 接口能否继承接口?抽象类能否实现接口?抽象类能否继承非抽象的类?
- 可以
- 可以
- 可以
- 声明抽象类,并包含抽象方法。测试类中创建一个继承抽象类的匿名子类的对象。
abstract class A{
public abstract void getData();
}
public class C{
public static void main(String[] args){
//匿名子类的非匿名对象
A a = new A(){
public void getData(){
}
};
}
}
- 抽象类和接口有哪些共同点和区别?
- 共同点:
- 都不能被实例化。
- 子类(或实现类)必须重写父类(或接口)的所有抽象方法,如果全部重写,此类可以实例化;如果没有全部重写,此类不可以被实例化(需要在加入关键词
abstract
)
- 不同点:
- 接口:
- 不能有构造器。
- 实现类通过
implements
实现 - 多实现。
- 抽象类:
- 有构造器。
- 子类通过
extends
继承 - 单继承。
- 接口:
- 共同点:
- 如何创建静态成员内部类和非静态内部类的对象?
- 静态成员内部类:
外部类.内部类 标识符 = new 外部类.内部类();
- 非静态成员内部类:
外部类 标识符1 = new 外部类();
外部类.内部类 标识符2 = 标识符1.new 内部类();
- 静态成员内部类:
本文由 Gorrywang 创作,严禁转载与复制!
最后编辑时间为: Aug 25,2016