目录
抽象类与抽象方法
概念
抽象类应用
接 口
概念
接口的特点:
接口应用举例
Java 8中关于接口的改进
内部类
如何声明局部内部类
局部内部类的特点
匿名内部类
总结
抽象类与抽象方法
概念
随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更一 般,更通用。类的设计应该保证父类和子类能够共享特征。有时将一个父类设计得非常抽象,以至于它没有具体的实例,这样的类叫做抽象类。
用abstract关键字来修饰一个类,这个类叫做抽象类。
抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法,并提供方法体。若没有重写全部的抽象方法,仍为抽象类。
用abstract来修饰一个方法,该方法叫做抽象方法。
抽象方法:只有方法的声明,没有方法的实现。以分号结束:public abstract void talk();
含有抽象方法的类必须被声明为抽象类。
- 不能用abstract修饰变量、代码块、构造器;
- 不能用abstract修饰私有方法、静态方法、final的方法、final的类。
abstract class A {
abstract void m1();
public void m2() {
System.out.println("A类中定义的m2方法");
}
}
class B extends A {
void m1() {
System.out.println("B类中定义的m1方法");
}
}
public class Test {
public static void main(String args[]) {
A a = new B();
a.m1();
a.m2();
}
}
抽象类应用
在航运公司系统中, Vehicle 类需要定义两个方法分别计算运输工具的燃料效率和行驶距离。卡车 (Truck) 和驳船 (RiverBarge) 的燃料效率和行驶距离的计算方法完全不同。Vehicle 类不能提供计算方法,但子类可以。
public abstract class Vehicle{
public abstract double calcFuelEfficiency(); //计算燃料效率的抽象方法
public abstract double calcTripDistance(); //计算行驶距离的抽象方法
}
public class Truck extends Vehicle{
public double calcFuelEfficiency( ) { //写出计算卡车的燃料效率的具体方法 }
public double calcTripDistance( ) { //写出计算卡车行驶距离的具体方法 }
}
public class RiverBarge extends Vehicle{
public double calcFuelEfficiency( ) { //写出计算驳船的燃料效率的具体方法 }
public double calcTripDistance( ) { //写出计算驳船行驶距离的具体方法}
}
接 口
概念
一方面,有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
另一方面,有时必须从几个类中抽取出一些共同的行为特征,而它们之间又 没有is-a的关系,仅仅是具有相同的行为特征而已。例如:鼠标、键盘、打 印机、扫描仪、摄像头、充电器、MP3机、手机、数码相机、移动硬盘等都 支持USB连接。
接口就是规范,定义的是一组规则,体现了现实世界中“如果你是/要...则必须能...”的思想。
继承是一个"是不是"的关系,而接口实现则是 "能不能" 的关系。 接口的本质是契约,标准,规范,就像我们的法律一样。制定好后大家都要遵守。
接口(interface)是抽象方法和常量值定义的集合。
接口的特点:
- 用interface来定义。
- 接口中的所有成员变量都默认是由public static final修饰的。
- 接口中的所有抽象方法都默认是由public abstract修饰的。
- 接口中没有构造器。
- 接口采用多继承机制。
public interface Runner {
public static final int ID = 1;
public abstract void start();
public abstract void run();
public abstract void stop();
}
定义Java类的语法格式:先写extends,后写implements
class SubClass extends SuperClass implements InterfaceA{ }
一个类可以实现多个接口,接口也可以继承其它接口。
实现接口的类中必须提供接口中所有方法的具体实现内容,方可实例化。否则,仍为抽象类。
接口的主要用途就是被实现类实现。(面向接口编程)
与继承关系类似,接口与实现类之间存在多态性
接口和类是并列关系,或者可以理解为一种特殊的类。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义 (JDK7.0及之前),而没有变量和方法的实现。
接口应用举例
interface Runner {
public void start();
public void run();
public void stop();
}
class Person implements Runner {
public void start() {
// 准备工作:弯腰、蹬腿、咬牙、瞪眼
// 开跑
}
public void run() {
// 摆动手臂
// 维持直线方向
}
public void stop() {
// 减速直至停止、喝水。
}
}
Java 8中关于接口的改进
Java 8中,你可以为接口添加静态方法和默认方法。从技术角度来说,这是完 全合法的,只是它看起来违反了接口作为一个抽象定义的理念。
静态方法:使用 static 关键字修饰。可以通过接口直接调用静态方法,并执行 其方法体。我们经常在相互一起使用的类中使用静态方法。你可以在标准库中找到像Collection/Collections或者Path/Paths这样成对的接口和类。
默认方法:默认方法使用 default 关键字修饰。可以通过实现类对象来调用。 我们在已有的接口中提供新方法的同时,还保持了与旧版本代码的兼容性。 比如:java 8 API中对Collection、List、Comparator等接口提供了丰富的默认方法。
public interface AA {
double PI = 3.14;
public default void method()
System.out.println("北京");
}
default String method1() {
return "上海";
}
public static void method2() {
System.out.println(“hello lambda!");
}
}
若一个接口中定义了一个默认方法,而另外一个接口中也定义了一个同名同 参数的方法(不管此方法是否是默认方法),在实现类同时实现了这两个接口时,会出现:接口冲突。
解决办法:实现类必须覆盖接口中同名同参数的方法,来解决冲突。
若一个接口中定义了一个默认方法,而父类中也定义了一个同名同参数的非抽象方法,则不会出现冲突问题。
因为此时遵守:类优先原则。接口中具有相同名称和参数的默认方法会被忽略。
内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使 用内部类。
- 在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者称为外部类。
- Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完整的名称。
- Inner class的名字不能与包含它的外部类类名相同;
- 成员内部类(static成员内部类和非static成员内部类) 局部内部类(不谈修饰符)、匿名内部类
class Outer {
private int s;
public class Inner {
public void mb() {
s = 100;
System.out.println("在内部类Inner中s=" + s);
}
}
public void ma() {
Inner i = new Inner();
i.mb();
}
}
public class InnerTest {
public static void main(String args[]) {
Outer o = new Outer();
o.ma();
}
}
如何声明局部内部类
只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方都不能使用该类
但是它的对象可以通过外部方法的返回值返回使用,返回值类型只能是局部内部类的父类或父接口类型
局部内部类的特点
内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号,以及数字编号。
- 只能在声明它的方法或代码块中使用,而且是先声明后使用。除此之外的任何地方 都不能使用该类。
- 局部内部类可以使用外部类的成员,包括私有的。
- 局部内部类可以使用外部方法的局部变量,但是必须是final的。由局部内部类和局部变量的声明周期不同所致。
- 局部内部类和局部变量地位类似,不能使用public,protected,缺省,private
- 局部内部类不能使用static修饰,因此也不能包含静态成员
匿名内部类
new 父类构造器(实参列表) | 实现接口 (){// 匿名内部类的类体部分}
- 匿名内部类必须继承父类或实现接口
- 匿名内部类只能有一个对象
- 匿名内部类对象只能使用多态形式引用
总结
package com.jyc.p2;
/*
* 一 abstract(抽象的) 关键字
* abstract 可以用来修饰的结构 类 方法
*
* Person1 修饰类 抽象类
* 此类不能实例化
* 抽象类中一定有构造器,便于子类实例化调用
* 开发中都会提供抽象类的子类 让子类实例化,完成相关操作
*
* Person1 修饰方法 抽象方法
* 抽象方法只有方法的声明,没有方法体
* 包含抽象方法的类,一定是一个抽象类,反之抽象类中可以没有抽象方法
* 若子类重写了父类中所有的抽象方法后,此子类可以实例化,
* 若子类没有重写父类中所有的抽象方法则此子类也是一个抽象类 需要使用abstract修饰
*
* abstract 使用上的注意点
* abstract不能用来修饰 属性 构造器等结构
* abstract 不能用来修饰私有方法(private) 静态方法 (static) final的方法 final的类
*
* 二 接口的使用 interface
* ① 接口使用 interface来定义
* ② java中接口和类是两个并列的机构
* ③ 如何定义接口 定义接口中的成员
* 1. jdk7及以前 只能定义全局常量和抽象方法
* 全局常量 public static final的 可以省略
* 抽象方法 public abstract void walk();可以省略
* 2. jdk8 增加了静态方法 默认方法
* ① 接口中定义的静态方法只能通过接口来调用
* ② 通过实现类的对象;可以调用接口中的默认方法
* ③ 如果实现类重写了接口中的默认方法,调用时仍然调用的是重写的方法
* ④如果子类(或实现类)继承的父类和实现接口声明了同名同参数的方法,那么子类在没有重写此方法的情况下
* 默认调用父类中的同名同参数方法(类优先原则)
* ⑤ 如果实现类实现了多个接口,而这多个接口中定义了同名同参数的方法,那么在实现类没有重写此
* 方法的情况下,报错------接口冲突(必选在接口类中重写此方法)
*
* ④ 接口中不能定义构造器,不可以实例化
* ⑤ java开发中接口让类去实现(implements)的方式使用
* 如果类覆盖了接口中所有的抽象方法,则此类就可以实例化
* 如果类没有覆盖接口中所有的抽象方法,则此实现类扔为一个抽象类
* ⑥ java类可以实现多个接口,弥补了java单继承性的局限性
* 格式:class AA extends BB implements CC,DD
* ⑦ 接口与接口之间可以继承,并且可以多继承
* ⑧ 接口的具体使用体现多态性
* ⑨ 接口实际上可以看做一种规范
*
*
* 三 内部类
* java中允许一个类a声明在一个类b中,则类a是内部类,类b称为外部类
* 内部类的分类 成员内部类 vs局部内部类(方法内,代码块内 构造器内)
* 成员内部类
* 一方面作为外部类的成员,
* 调用外部类的结构
* 可以用static 修饰
* 可以被四种不同权限修饰
*
* 另一方面作为一个类
* 类内可以定义属性 方法 构造器
* 可以被final 修饰,表示类不能被继承,不使用可以继承
* 可以被 abstract修饰 不能被实例化
*
*关注一下三个问题
* 如何实例化成员内部类
* 如何在成员内部类中区分调用外部类的结构
* 开发中局部内部类的使用
*
*
*
*
* */
public class abstracTest {
public static void main(String[] args) {
// Person1 p1=new Person1(); 不可以实例化
// 创建一个匿名子类对象
Person1 p1=new Person1() {
public void walk() {
System.out.println("匿名子类对象 重写walk");
}
};
abstracTest.methods(p1);
System.out.println("-----接口-------");
Plane p2=new Plane();
p2.fly();//接口的使用
CompareA.methods(); //接口静方法只能通过接口调用
subClass s1=new subClass();
s1.methods1();//执行实现类重写的方法
s1.methods(); //父类优先
System.out.println("---------调用-------");
s1.Mymethods();
System.out.println("---------内部类-------");
//静态成员内部类
InnerClassTest.Cat cat=new InnerClassTest.Cat();
cat.show();
InnerClassTest c5=new InnerClassTest();
InnerClassTest.Dog dog= c5.new Dog();
dog.show();
}
public static void methods(Person1 p){
p.walk();
}
}
abstract class Person1{
String name;
int age;
public Person1(){}
public Person1(String name, int age){
this.name=name;
this.age=age;
}
public abstract void walk();
public void eat(){
System.out.println("人吃饭");
}
}
class Student1 extends Person{
public Student1(String name, int age){
super(name, age);
}
public void walk(){
System.out.println("跑");
};
}
interface Flyble{
public static final int Maxs=7990;
int mians=1;
public abstract void fly();
void Stop();
}
interface Attackable{
void attack();
}
class Plane implements Flyble{
@Override
public void fly() {
System.out.println("飞机飞");
}
@Override
public void Stop() {
System.out.println("飞机停止");
}
}
class Bullet extends Object implements Flyble,Attackable{
public void fly() {
}
@Override
public void Stop() {
}
public void attack(){
}
}
interface CompareA{
//静态方法
public static void methods(){
System.out.println("北京");
};
//默认方法
public default void methods1(){
System.out.println("上海");
}
public default void methods3(){
System.out.println("杭州");
}
}
interface CompareB{
//默认方法
public default void methods3(){
System.out.println("上海");
}
}
class superClass{
public void methods(){
System.out.println("父类方法,北京");
};
}
class subClass extends superClass implements CompareA,CompareB{
public void methods1(){
System.out.println("subClass 重写默认方法");
}
public void methods3(){
System.out.println("类冲突实现类必选重写 杭州");
}
//如何在子类(或实现类)的方法中调用父类 ,接口中被重写的方法
public void Mymethods(){
methods1();//调用自己重写的
super.methods();//调用父类重写的
CompareA.super.methods1();//调用接口中默认方法
}
}
class InnerClassTest{
//成员内部类
public void eat(){
System.out.println("吃");
}
class Dog{
public void show(){
System.out.println("狗");
InnerClassTest.this.eat();
}
};
static class Cat{
public void show(){
System.out.println("猫");
}
};
public void methods(){
//内部类
class AA{}
}
{
//内部类
class BB{}
}
public InnerClassTest(){
//内部类
class CC{}
}
}