抽象类和抽象方法:

抽象方法:
使用abstract修饰的方法,没有方法体,只有声明.定义的是一种“规范”,就是告诉子类必须要给抽象方法
提供具体的实现.

抽象类:
包含抽象方法的类就是抽象类.通过abstract方法定义规范,然后要求子类必须定义具体实现.通过抽象类,
我们就可以做到严格限制子类的设计,使子类之间更加通用.

注意:
1. 有抽象方法的类只能定义成抽象类
2. 抽象类不能实例化,即不能用new来实例化抽象类.
3. 抽象类可以包含属性、方法、构造方法.但是构造方法不能用来new实例,只能用来被子类调用.
4. 抽象类只能用来被继承.
5. 抽象方法必须被子类实现.

例子:

public abstract class Animal {
// 抽象方法
abstract public void shout();
// 抽象类中可以定义其他普通方法
public static void main(String[] args) {
// Animal a1 = new Animal();
// 抽象类不能new其实例,但可以用其类型
Animal a1 = new Dog();
a1.shout();
}

}

class Dog extends Animal{
//子类必须实现父类的抽象方法,否则编译错误
// 并且此方法的访问权限必须与父类一致
public void shout() {
System.out.println("汪汪");
}


public void seeDoor () {
System.out.println("看门中....");
}
}

interface接口:

抽象类还提供某些具体实现,而接口则不提供任何实现,接口中所有方法都是抽象方法.
接口是完全面向规范的,规定了一批类具有的公共方法规范.

接口和实现类不是父子关系,是实现规则的关系.

1. 普通类:具体实现
2. 抽象类:具体实现,规范(抽象方法)
3. 接口:规范!

声明格式:
[访问修饰符] interface 接口名 [extends 父接口1,父接口2…] {
常量定义;
方法定义;
}

说明:
1. 访问修饰符:只能是public或默认.
 2. 接口名:和类名采用相同命名机制.
 3. extends:接口可以多继承.
 4. 常量:接口中的属性只能是常量,总是:public static final 修饰.不写也是.
 5. 方法:接口中的方法只能是:public abstract. 省略的话,也是public abstract.

要点:
1. 子类通过implements来实现接口中的规范.
2. 接口不能创建实例,但是可用于声明引用变量类型.
3. 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的.
4. JDK1.7之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法.
5. JDK1.8后,接口中包含普通的静态方法.

例子:
public interface MyInsterface {

void fly(); // abstract public void fly();

int MAX_NUM = 100; // public static final int MAX_NUM = 100;
}

interface Beautiful{
double PI = 3.14; // 总是:public static final类型的;
void dress(); // 总是:public abstract void dress();
}

class Angle implements MyInsterface, Beautiful{
// 必须实现implements后所有接口的所有方法
@Override
public void dress() {
System.out.println("Beau ...");

}

@Override
public void fly() {

System.out.println("My ....");
}

public static void main(String[] args) {
// 接口不能创建实例,但是可用于声明引用变量类型.
// new的对象必须为其接口的实现类
MyInsterface infac = new Angle();
// 用接口类型的对象只能调用类中(在这个接口中拥有有的)方法
infac.fly();
// 可以调用接口中的常量成员
System.out.println(infac.MAX_NUM);
}

}

接口的多继承:
接口支持多继承.和类的继承类似,子接口扩展某个父接口,将会获得父接口中所定义的一切.

例:
interface A {
void testa();
}

interface B {
void testb();
}

/**接口可以多继承:接口C继承接口A和B*/
interface C extends A, B {
void testc();
}

public class Test implements C {
public void testc() {
}
public void testa() {
}
public void testb() {
}
}

内部类:

一般情况,我们把类定义成独立的单元.有些情况下,我们把一个类放在另一个类的内部定义,
称为内部类(innerclasses).

内部类可以使用public、default、protected 、private以及static修饰.而外部顶级类
(我们以前接触的类)只能使用public和default修饰.

注意:
内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类.对于一个名为Outer的外部类
和其内部定义的名为Inner的内部类.编译完成后会出现Outer.class和Outer$Inner.class两个类的字节码文件.
所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同.

内部类的作用:

1. 内部类提供了更好的封装.只能让外部类直接访问,不允许同一个包中的其他类直接访问.
2. 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员. 但外部类不能访问内部类的内部属性.
3. 接口只是解决了多重继承的部分问题,而内部类使得多重继承的解决方案变得更加完整.

内部类的使用场合:

1. 由于内部类提供了更好的封装特性,并且可以很方便的访问外部类的属性.所以,在只为外部类提供服务的情况下
可以优先考虑使用内部类.
2. 使用内部类间接实现多继承:每个内部类都能独立地继承一个类或者实现某些接口,所以无论外部类是否已经继承
了某个类或者实现了某些接口,对于内部类没有任何影响.

内部类的分类

在Java中内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、局部内部类.
成员内部类(可以使用private、default、protected、public任意进行修饰. 类文件:外部类$内部类.class)

-------------------------------------------------------------------------------------------
a) 非静态内部类(外部类里使用非静态内部类和平时使用其他类没什么不同)

1) 非静态内部类必须寄存在一个外部类对象里.因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象.
非静态内部类对象单独属于外部类的某个对象.
2) 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员.
3) 非静态内部类不能有静态方法、静态属性和静态初始化块.
4) 外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例.

成员变量访问要点:
1. 内部类里方法的局部变量:变量名.
2. 内部类属性:this.变量名.
3. 外部类属性:外部类名.this.变量名.

例子:
public class TestInnerClass {
public static void main(String[] args) {
// 创建非静态成员内部类的对象
Outer.Inner inobj = new Outer().new Inner();
inobj.show();
}
}


class Outer{
// 外部类的成员变量
private int age = 10;
String name = "123";
public void testOuter() {
外 System.out.println("Outer.testOuter");
}

class Inner{
// 内部类的成员变量
int age = 18;
public void show() {
// 局部变量
int age = 20;
System.out.println("外部类的成员变量age:" + Outer.this.age);
System.out.println("内部类的成员变量age:" + this.age);
System.out.println("内部类的成员函数中的局部变量age:" + age);
}
}
}

-------------------------------------------------------------------------------------------
b) 静态内部类
1) 定义方式:
static class 类名 {
//类体
}

2) 使用要点:
i. 当一个静态内部类对象存在,并不一定存在对应的外部类对象. 因此,静态内部类的实例方法不能直接访问
外部类的实例方法.

ii. 静态内部类看做外部类的一个静态成员. 因此,外部类的方法中可以通过:“静态内部类.名字”的方式访问
静态内部类的静态成员,通过 new 静态内部类()访问静态内部类的实例.

例子:
public class TestStaticInnerClass {
public static void main(String[] args) {
// 创建静态成员内部类的对象
Outer2.Inner2 staticInner = new Outer2.Inner2();
}
}

class Outer2{
private String name = "张三";
static int age = 12;

static class Inner2{
}
}
-------------------------------------------------------------------------------------------
c) 匿名内部类

适合那种只需要使用一次的类.比如:键盘监听操作等等.

语法:
new 父类构造器(实参类表) \实现接口 () {
//匿名内部类类体!
}

例子:
// WindowAdapter一个接口,本来没有实现其中的方法是不可以new的
// 但是可以用匿名内部类,在内部类中实现

// new WindowAdapter() 实际上是实例化了一个WindowAdapter的子类的对象,
// 这个子类没有名称,但指u明它是WindowAdapter的子类,
// 它覆盖了父类WindowAdapter的windowClosing方法.WindowAdapter是抽象类,
// 它实现了WindowListener,但是它的每一个方法体都是空的

this.addWindowListener(new WindowAdapter(){
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
);

this.addKeyListener(new KeyAdapter(){
@Override
public void keyPressed(KeyEvent e) {
myTank.keyPressed(e);
}
@Override
public void keyReleased(KeyEvent e) {
myTank.keyReleased(e);
}
}
);

注意:
1. 匿名内部类没有访问修饰符.
2. 匿名内部类没有构造方法.(没有名字,所以肯定没构造方法)
------------------------------------------------------------------------------------------