抽象类与抽象方法(abstract)
abstract关键字的使用
-
abstract:抽象的
-
abstract可以用来修饰的结构:类、方法
-
abstract修饰类:抽象类
》 此类不能实例化(不能造对象)
》 抽象类中一定有构造器,便于子类对象实例化的时候调用(涉及:子类对象实例化的全过程 )
》开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作 -
abstract修饰方法:抽象方法
》抽象方法只有方法的声明,没有方法体
》包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的
》若子类重写了父类中的所有的抽象方法后,此子类方可实例化
若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰 -
abstract使用上的注意点:
》abstract不能用来修饰:属性、构造器等结构
》abstract不能用来 修饰私有方法、静态方法、final的方法
多态对于抽象类很重要,如果没有多态那么抽象类就没有意义了。
- 假如我们去声明一个方法,这个方法有个形参(类 类型)如果这个类是抽象类,这个时候就必须要用多态,因为这个类本身就不能造对象,所以只能通过多态来造对象。
创建抽象类的匿名子类
/*
* 抽象类的匿名子类
*
*/
public class PersonTest {
public static void main(String[] args) {
method(new Student());//匿名对象
Worker worker = new Worker();
method1(worker);//非匿名的类非匿名的对象
method1(new Worker());//非匿名的类匿名的对象
System.out.println("********************");
//创建了一匿名子类的对象:p
Person p = new Person(){
@Override
public void eat() {
System.out.println("吃东西");
}
@Override
public void breath() {
System.out.println("好好呼吸");
}
};
method1(p);
System.out.println("********************");
//创建匿名子类的匿名对象
method1(new Person(){
@Override
public void eat() {
System.out.println("吃好吃东西");
}
@Override
public void breath() {
System.out.println("好好呼吸新鲜空气");
}
});
}
public static void method1(Person p){
p.eat();
p.breath();
}
public static void method(Student s){
}
}
class Worker extends Person{
@Override
public void eat() {
}
@Override
public void breath() {
}
}
模板方法设计模式
接口:
- 接口的使用
- 1.接口使用interface来定义
- 2.Java中,接口和类是并列的两个结构
- 3.如何定义接口:定义接口中的成员
- 3.1 JDK7及以前:只能定义全局常量和抽象方法
》全局常量:public static final的.但是书写时,可以省略不写
》抽象方法:public abstract的 - 3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略)
- 4.接口中不能定义构造器的!意味着接口不可以实例化
- 5.Java开发中,接口通过让类去实现(implements)的方式来使用.
- 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化
- 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类
- 6.Java类可以实现多个接口 →弥补了Java单继承性的局限性
- 格式:class AA extends BB implements CC,DD,EE
- 7.接口与接口之间可以继承,而且可以多继承
- 8.接口的具体使用,体现多态性
- 9.接口,实际上可以看做是一种规范
接口使用上也满足多态性,接口实际上就是定义了一种规范
package com.acoffee.java1;
public class USBTest {
public static void main(String[] args) {
Computer com = new Computer();
Flash flash = new Flash();
com.transferData(flash);
}
}
class Computer{
public void transferData(USB usb) {//USB usb = new Flash();
usb.start();
System.out.println("具体传输数据的细节");
usb.stop();
}
}
interface USB{
//定义了长、宽、最大最小的传输速度
void start();
void stop();
}
class Flash implements USB{
@Override
public void start() {
System.out.println("U盘开启工作");
}
@Override
public void stop() {
System.out.println("U盘结束工作");
}
}
class printer implements USB{
@Override
public void start() {
System.out.println("打印机开始工作");
}
@Override
public void stop() {
System.out.println("打印机结束工作");
}
}
执行结果:
U盘开启工作
具体传输数据的细节
U盘结束工作
接口的应用:
/*
* 接口的应用:代理模式
*
*/
public class NetWorkTest {
public static void main(String[] args) {
Server server = new Server();
// server.browse();
ProxyServer proxyServer = new ProxyServer(server);
proxyServer.browse();
}
}
interface NetWork{
public void browse();
}
//被代理类
class Server implements NetWork{
@Override
public void browse() {
System.out.println("真实的服务器访问网络");
}
}
//代理类
class ProxyServer implements NetWork{
private NetWork work;
public ProxyServer(NetWork work){
this.work = work;
}
public void check(){
System.out.println("联网之前的检查工作");
}
@Override
public void browse() {
check();
work.browse();
}
}
执行结果:
联网之前的检查工作
真实的服务器访问网络
面试题:
这个是接口和类都是x重名了所以编译器不知道该用哪一个。可以将其改名,或者你如果想继承父类的话直接(super.x).就可以了。
这个是因为ball是不能被重写的在接口里面的这个ball是前面还有static 和 final是被省略了的所以不能重写。只能定义全局常量。
练习:
CompareObject 类:
package com.acoffee.exer3;
public interface CompareObject {
//若返回值是 0 , 代表相等; 若为正数,代表当 前对象大;负数代表当前对象小
public int compareTo(Object o);
}
Circle类:
package com.acoffee.exer3;
public class Circle {
private double radius;
public Circle() {
}
public Circle(double radius){
this.radius = radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double getRadius() {
return radius;
}
}
ComparableCircle类:
package com.acoffee.exer3;
public class ComparableCircle extends Circle implements CompareObject{
public ComparableCircle(double radius) {
super(radius);
}
@Override
public int compareTo(Object o) {
if(this == o) {
return 0;
}
if(o instanceof ComparableCircle) {
ComparableCircle c = (ComparableCircle)o;
//错误的:int会让精度损失
//return (int)(this.getRadius() - c.getRadius());
//正确的:
if(this.getRadius() > c.getRadius()) {
return 1;
}else if(this.getRadius() < c.getRadius()) {
return -1;
}else {
return 0;
}
}
return 0;
}
}
ComparableCircleTest类:
package com.acoffee.exer3;
public class ComparableCircleTest {
public static void main(String[] args) {
ComparableCircle c1 = new ComparableCircle(3.4);
ComparableCircle c2 = new ComparableCircle(3.6);
int compareValue = c1.compareTo(c2);
if(compareValue > 0) {
System.out.println("c1大");
}else if(compareValue < 0) {
System.out.println("c2大");
}else {
System.out.println("一样大");
}
}
}
执行结果:
c2大
java8中接口的新特性:
知识点一:接口定义的静态方法,只能通过接口来调用
interface A {
public static void test() {
System.out.println("1");
}
}
public class CompareTest implements A {
public void Px() {
A.test();
}
public static void main(String[] args) {
new CompareTest().Px();
}
}
知识点二:通过实现类的对象,可以调用接口中的默认方法。如果实现类重写了接口的默认方法,调用时,调用的是重写以后的方法。
interface A {
default void test() {
System.out.println("1");
}
}
public class CompareTest implements A {
public void Px() {
test();
}
public static void main(String[] args) {
new CompareTest().Px();
}
}
知识点三:如果子类(或实现类)继承的父类和实现的接口中声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用的是父类中的同名参数的方法。 ----类优先原则
public class CompareTest extends B implements A {
public void Px() {
test();
}
public static void main(String[] args) {
new CompareTest().Px();
}
}
interface A {
default void test() {
System.out.println("1");
}
}
class B {
public void test(){
System.out.println("2");
}
}
知识点四:如果实现类实现类多个接口,而这多个接口中定义了同名同参数的默认方法,那么在实现类没有重写此方法的情况下,报错-----接口冲突 这就需要我们重写此方法。
知识点五:如何在子类(或实现类)的方法中调用父类、接口中被重写的方法?
类的成员之五:内部类
1.Java中允许将一个类A声明在另一个类B中,则类A就是内部类
2.内部类的分布:成员内部类(静态、非静态)vs 局部内部类(方法类、代码块内、构造器内)
3.成员内部类:
一方面,作为外部类的成员:
- 调用外部类的结构
- 可以被static修饰
- 可以被4中不同的权限修饰
另一方面,作为一个类:
- 类内可以定义属性、方法、构造器等
- 可以被final修饰,表示此类不能被继承。言外之意,不使用final可以被继承
- 可以被abstract修饰
4.匿名内部类
什么是的匿名内部类?
- 就是没有名字的局部内部类,本质是一种对象。
new类名/接口名(){
//自己特有的方法
//重写的方法
};
new Person(0) {};
我们什么时候可以使用匿名内部类?
当一个方法的形参类型是一个抽象类或者接口类型的时候,那我们就可以选择使用匿名内部类
interface Inter {
void eat();
void drink();
}
class Test1 {
public static void main(String[] args) {
Inter inter = new Inter() {
public void eat() {
System.out.println("吃饭");
}
public void drink() {
System.out.println("喝酒");
}
public void visit() {
System.out.println("旅游");
}
};
inter.drink();
inter.eat();
new Inter() {
public void eat() {
System.out.println("吃饭");
}
public void drink() {
System.out.println("喝酒");
}
public void visit() {
System.out.println("旅游");
}
}.visit();
}
}
执行结果:
喝酒
吃饭
旅游
5.关注如下三个问题:
1.如何实例化成员内部类的对象
2.如何在成员内部类中区分外部类的的结构
如果重名:
3.注意点:
package com.acoffee.exer2;
public class InnerClassTest {
//在局部内部类的方法中(比如:show)如果调用局部内部类
//所声明的方法(比如:method)中的局部变量(比如:num)
//要求次局部变量声明为final的。
//jdk 7及之前版本,要求此局部变量显式的声明为final的
//jdk 8及之后的版本,可以省略final 的声明
public void method() {
//局部变量
int num = 10;//前面相当于有final 只是被省略
class AA{
public void show() {
//num = 20; 不能被重新声明
System.out.println(20);
}
}
}
}
4.开发中局部内部类的使用
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;
}
};
}
}
每日一练:
1. abstract 能修饰哪些结构? 修饰以后,有什么特点?
类、方法。
类不能实例化,提供子类
抽象方法,只定义了一种功能的标准。具体的执行,需要子类去实现。
2. 接口是否能继承接口? 抽象类是否能实现(implements)接口? 抽象类是否能继承非抽象的类?
能,能,能
3. 声明抽象类,并包含抽象方法。测试类中创建一个继承抽象类的匿名子类的对象
abstract AA{
public abstract void m();
}
main(){
AA a = new AA(){
public void m(){
}
};
a.m();
}
class Person{
String name;
public void eat(){}
}
main(){
Person p = new Person(){
public void eat(){}
};
p.eat();
}
4. 抽象类和接口有哪些共同点和区别?
相同点:不能实例化,都可以被继承
不同点:抽象类:有构造器。 接口:不能声明构造器
多继承vs 单继承
5. 如何创建静态成员内部类和非静态成员内部类的对象?
Person static Dog Bird
Person.Dog dog = new Person.Dog();
Person p = new Person();
Person.Bird bird = p.new Bird();