目录
接口
接口的本质
接口与抽象类的区别
抽象类也是类,除了可以写抽象方法以及不能直接new对象之外,其他的和普通类没有什么不一样的。接口已经另一种类型了,和类是有本质的区别的,所以不能用类的标准去衡量接口。
声明类的关键字是
class,
声明接口的关键字是
interface
。
抽象类是用来被继承的,java中的类是单继承。
类A继承了抽象类B,那么类A的对象就属于B类型了,可以使用多态
一个父类的引用,可以指向这个父类的任意子类对象
注
:
继承的关键字是
extends
接口是用来被类实现的,java中的接口可以被多实现。
类A实现接口B、C、D、E..,那么类A的对象就属于B、C、D、E等类型了,可以使用多态
一个接口的引用,可以指向这个接口的任意实现类对象
注
:
实现的关键字是
implements
接口中的方法都是抽象方法
public interface Action{
public abstract void run();
//默认就是public abstract修饰的
//可以直接写成
void test();
}
接口中的变量都是静态常量
属性必须是public static fifinal修饰的静态常量。
注:可以直接使用接口名访问其属性。因为是public static修饰的
注:声明的同时就必须赋值.(因为接口中不能编写静态代码块)
public interface Action{
public static final String NAME = "tom";//String name ="tom"
//默认就是public static final修饰的
int AGE = 20;
}
main:
System.out.println(Action.NAME);
System.out.println(Action.AGE);
一个类可以实现多个接口
public class Student implements A,B,C,D{
//Student需要实现接口A B C D中所有的抽象方法
//否则Student类就要声明为抽象类,因为有抽象方法没实现
}
main:
A s1 = new Student();//s1只能调用接口A中声明的方法以及Object中的方法
B s2 = new Student();//s2只能调用接口B中声明的方法以及Object中的方法
C s3 = new Student();//s3只能调用接口C中声明的方法以及Object中的方法
D s4 = new Student();//s4只能调用接口D中声明的方法以及Object中的方法
// 必要时可以类型强制转换
//接口A中有test() ,接口B中有run()
A s1 = new Student();
s1.test();
B s2 = new Student();
s2.run();
if(s1 instanceof B){
((B)s1).run();
}
一个接口可以继承多个父接口
public interface A{
public void testA();
}
public interface B{
public void testB();
}
//接口C把接口A B中的方法都继承过来了
public interface C extends A,B{
public void testC();
}
//Student相当于实现了A B C三个接口,需要实现所有的抽象方法
//Student的对象也就同时属于A类型 B类型 C类型
public class Student implements C{
public viod testA(){}
public viod testB(){}
public viod testC(){}
}
main:
C o = new Student();
System.out.println(o instanceof A);//true
System.out.println(o instanceof B);//true
System.out.println(o instanceof C);//true
System.out.println(o instanceof Student);//true
System.out.println(o instanceof Object);//true
System.out.println(o instanceof Teacher);//false
//编译报错 System.out.println(o instanceof String);
System.out.println(o instanceof X);
如果o是一个接口类型声明的变量,那么只要X不是一个final修饰的类,该代码就能通过编译,至于其结果是不是true,就要看变量o指向的对象的实际类型,是不是X的子类或者实现类了。
接口的作用
接口的最主要的作用是达到统一访问,就是在创建对象的时候用接口创建
【接口名】 【对象名】= new 【实现接口的类】
1、Java接口中的成员变量默认都是public,static,fifinal类型的(都可省略),必须被显示初始化,即接
口中的成员变量为常量(大写,单词之间用"_"分隔)
2、Java接口中的方法默认都是public,abstract类型的(都可省略),没有方法体,不能被实例化
3、Java接口中只能包含public,static,fifinal类型的成员变量和public,abstract类型的成员方法
4、接口中没有构造方法,不能被实例化
5、一个接口不能实现(implements)另一个接口,但它可以继承多个其它的接口
6、Java接口必须通过类来实现它的抽象方法
7、当类实现了某个Java接口时,它必须实现接口中的所有抽象方法,否则这个类必须声明为抽象
类
8、不允许创建接口的实例(实例化),但允许定义接口类型的引用变量,该引用变量引用实现了这
个接口的类的实例
9、 一个类只能继承一个直接的父类,但可以实现多个接口,间接的实现了多继承.
interface SwimInterface{
void swim();
}
class Fish{
int fins=4;
}
class Duck {
int leg=2;
void egg(){};
}
class Goldfish extends Fish implements SwimInterface {
@Override public void swim() {
System.out.println("Goldfish can swim ");
}
}
class SmallDuck extends Duck implements SwimInterface {
public void egg(){
System.out.println("SmallDuck can lay eggs ");
}
@Override public void swim() {
System.out.println("SmallDuck can swim ");
}
}
public class InterfaceDemo {
public static void main(String[] args) {
Goldfish goldfish=new Goldfish();
goldfish.swim();
SmallDuck smallDuck= new SmallDuck();
smallDuck.swim();
smallDuck.egg();
}
}
内部类
内部类概述
内部类就是在一个类的内部在定义一个类
成员内部类(实例内部类、非静态内部类)
成员内部类中不能写静态属性和方法
//【定义一个内部类】
在A类中申明了一个B类,此B类就在A的内部,并且在成员变量的位置上,所以就称为成员内部类
public class Outer {
private int id;
public void out(){
System.out.println("这是外部类方法");
}
class Inner{
public void in(){
System.out.println("这是内部类方法");
}
}
}
//实例化内部类,首先需要实例化外部类,通过外部类去调用内部类
public class Outer {
private int id;
public void out(){
System.out.println("这是外部类方法");
}
class Inner{
public void in(){
System.out.println("这是内部类方法");
}
}
}
public class Test{ public static void main(String[] args) {
//实例化成员内部类分两步
//1、实例化外部类
Outer outObject = new Outer();
//2、通过外部类调用内部类
Outer.Inner inObject = outObject.new Inner();
//测试,调用内部类中的方法
inObject.in();
//打印:这是内部类方法
}
}
//1. 访问外部类的所有属性(这里的属性包括私有的成员变量,方法)
public class Outer {
private int id;
public void out(){
System.out.println("这是外部类方法");
}
class Inner{
public void in(){
System.out.println("这是内部类方法");
}
//内部类访问外部类私有的成员变量
public void useId(){
System.out.println(id+3);
}
//内部类访问外部类的方法
public void useOut(){
out();
}
}
}
public class Test{
public static void main(String[] args) {
//实例化成员内部类分两步
//1、实例化外部类
Outer outObject = new Outer();
//2、通过外部类调用内部类
Outer.Inner inObject = outObject.new Inner();
//测试
inObject.useId();//打印3,因为id初始化值为0,0+3就为3,其中在内部类就使用了 外部类的私有成员变量id。
inObject.useOut();//打印:这是外部类方法
}
}
//如果内部类中的变量名和外部类的成员变量名一样,要通过创建外部类对象 "."属性来访问外部类
属性,通过this.属性访问内部类成员属性
public class Outer {
private int id;//默认初始化0
public void out(){
System.out.println("这是外部类方法");
}
class Inner{
private int id=8; //这个id跟外部类的属性id名称一样。
public void in(){
System.out.println("这是内部类方法");
}
public void test(){
System.out.println(id);//输出8,内部类中的变量会暂时将外部类的成员变量给隐藏
//如何调用外部类的成员变量呢?通过Outer.this,想要知道为什么能通过这个来调用,就得明白下面这个原理
//想实例化内部类对象,就必须通过外部类对象,当外部类对象来new出内部类对象时,会
//把自己(外部类对象)的引用传到了内部类中,所以内部类就可以通过 Outer.this来访问外部类的属性和方法,到这里,你也就可以知道为什么内部类可以访问外部类的属性和方法,这里由于有两个相同的属性名称,所以需要显示的用Outer.this来调用外部类的属性,平常如果属性名不重复,那么我们在内部类中调用外部类的属性和方法时,前面就隐式的调用了Outer.this。
System.out.println(Outer.this.id);//输出外部类的属性id。也就是输出0
}
}
}
静态内部类
1)static修饰成员变量:整个类的实例共享静态变量
2)static修饰方法:静态方法,只能够访问用static修饰的属性或方法,而非静态方法可以访问static修饰的方法或属性
3)被static修饰了的成员变量和方法能直接被类名调用。
4)static不能修饰局部变量,切记,不要搞混淆了,static平常就用来修饰成员变量和方法。
public class StaticInnerClassTest {
private String name;
private static int age;
public void run(){}
public static void go(){}
//外部类访问静态内部类
public void test(){
StaticInnerClass sic = new StaticInnerClass(); //静态的内部类不需要依赖外部类,所以不用this
sic.name = "tom";
sic.test1("jack");
StaticInnerClass.age=10;
StaticInnerClass.test2("xixi");
}
private static class StaticInnerClass{
private String name;
private static int age;
public void test1(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(StaticInnerClass.age);
System.out.println(StaticInnerClassTest.age); //System.out.println(StaticInnerClassTest.this.name);静态类不能访问非静态属性
StaticInnerClassTest.go();
//StaticInnerClassTest.this.run();静态类不能访问非静态方法
}
public static void test2(String name){
//只能访问自己和外部类的静态属性和方法
System.out.println(name);
//System.out.println(this.name);静态方法里面连自己类的非静态属性都不能访问
System.out.println(StaticInnerClass.age);
System.out.println(StaticInnerClassTest.age); //System.out.println(StaticInnerClassTest.this.name);静态方法不能 访问非静态属性 StaticInnerClassTest.go();
//StaticInnerClassTest.this.run();静态方法不能访问非静态方法
}
}
}
1、我们上面说的内部类能够调用外部类的方法和属性,在静态内部类中就行了,因为静态内部类没有了指向外部类对象的引用。除非外部类中的方法或者属性也是静态的。这就回归到了static关键字的用法。
2、静态内部类能够直接被外部类给实例化,不需要使用外部类对象
Outer.Inner inner = new Outer.Inner();
3、静态内部类中可以声明静态方法和静态变量,但是非静态内部类中就不可以声明静态方法和静态变量.
局部内部类
局部内部类是在一个方法内部声明的一个类
局部内部类中可以访问外部类的成员变量及方法
局部内部类中如果要访问该内部类所在方法中的局部变量,那么这个局部变量就必须是final修饰的
public class Outer {
private int id;
//在method01方法中有一个Inner内部类,这个内部类就称为局部内部类
public void method01(){
class Inner{
public void in(){
System.out.println("这是局部内部类");
}
}
}
}
1. 在局部内部类中,如果要访问局部变量,那么该局部变量要用final修饰
public class Outer {
private int id;
public void method01(){
final int cid = 3; //这个就是局部变量cid。要让局部内部类使用,就得变为final并且赋值,如果不使用final修饰,就会报错
class Inner{
//内部类的第一个方法
public void in(){
System.out.println("这是局部内部类");
}
//内部类中的使用局部变量cid的方法
public void useCid(){
System.out.println(cid);
}
} } }
1. 局部内部类不能通过外部类对象直接实例化,而是在方法中实例化出自己来,然后通过内部类对象调用自己类中的方法。
public class Outer {
private int id;
public void out(){
System.out.println("外部类方法");
}
public void method01(){
class Inner{ public void in(){
System.out.println("这是局部内部类");
}
}
//关键在这里,如需要在method01方法中自己创建内部类实例,然后调用内部类中的方法,等待外部类调用method01方法,就可以执行到内部类中的方法了。
Inner In = new Inner();
In.in(); } }
使用局部内部类需要注意的地方就刚才上面说的:
1、在局部内部类中,如果要访问局部变量,那么该局部变量要用fifinal修饰
2、如何调用局部内部类方法。
public class LocalInnerClassTest {
private String name;
private static int age;
public void run(){}
public static void go(){}
//局部内部类要定义在方法中
public void test(){
final String myname="";
class LocalInnerClass{
private String name; // private static int age;不能定义静态属性
public void test(String name){
System.out.println(name);
System.out.println(this.name);
System.out.println(myname);
System.out.println(LocalInnerClassTest.this.name);
LocalInnerClassTest.this.run();
LocalInnerClassTest.go();
}
}
//局部内部类只能在自己的方法中用,因为局部内部类相当于一个局部变量,除了方法就找不到了。
LocalInnerClass lic = new LocalInnerClass();
lic.name="tom";
lic.test("test");
} }
匿名内部类!
如果一个对象只要使用一次,那么我们就是需要new Object().method()。 就可以了,而不需要给这个实例保存到该类型变量中去。这就是匿名对象。
public class Test {
public static void main(String[] args) {
//讲new出来的Apple实例赋给apple变量保存起来,但是我们只需要用一次,就可以这样写
Apple apple = new Apple();
apple.eat(); //这种就叫做匿名对象的使用,不把实例保存到变量中。
new Apple().eat();
}
}
class Apple{
public void eat(){
System.out.println("我要被吃了"); } }
匿名对象:我只需要用一次,那么我就不用声明一个该类型变量来保存对象了,
匿名内部类:我也只需要用一次,那我就不需要在类中先定义一个内部类,而是等待需要用的时候,我就在临时实现这个内部类,因为用次数少,可能就这一次,那么这样写内部类,更方便。不然先写出一个内部类的全部实现来,然后就调用它一次,岂不是用完之后就一直将其放在那,那就没必要那样。
1. 匿名内部类需要依托于其他类或者接口来创建
- 如果依托的是类,那么创建出来的匿名内部类就默认是这个类的子类
- 如果依托的是接口,那么创建出来的匿名内部类就默认是这个接口的实现类。
2. 匿名内部类的声明必须是在使用new关键字的时候
- 匿名内部类的声明及创建对象必须一气呵成,并且之后能反复使用,因为没有名字。
//A是一个类(普通类、抽象类都可以),依托于A类创建一个匿名内部类对象
main: A a = new A(){
//实现A中的抽象方法
//或者重写A中的普通方法
};
//注:这个大括号里面其实就是这个内部类的代码,只不过是声明该内部类的同时就是要new创建了其对象, 并且不能反复使用,因为没有名字。
// 例如: B是一个接口,依托于B接口创建一个匿名内部类对象
B b = new B(){ //实现B中的抽象方法 };
1. 匿名内部类除了依托的类或接口之外,不能指定继承或者实现其他类或接口,同时也不能被其他类所继承,因为没有名字。
2. 匿名内部中,我们不能写出其构造器,因为没有名字。
3. 匿名内部中,除了重写上面的方法外,一般不会再写其他独有的方法,因为从外部不能直接调用到。(间接是调用到的)
public interface Work{
void doWork();
}
public class AnonymousOutterClass{
private String name;
private static int age;
public void say(){}
public static void go(){}
public void test(){
final int i = 90;
Work w = new Work(){
public void doWork(){
System.out.println(AnonymousOutterClass.this.name); System.out.println(AnonymousOutterClass.age);
AnonymousOutterClass.this.say();
AnonymousOutterClass.go();
System.out.println(i);
}
};
w.doWork(); } }
//【不用匿名内部类】
public class Test {
public static void main(String[] args) {
//如果我们需要使用接口中的方法,我们就需要走3步,1、实现接口 2、创建实现接口类的实 例对象 3、通过对象调用方法
//第二步
Test02 test = new Test02();
//第三步
test.method();
}
}
//接口Test1
interface Test01{ public void method(); }
//第一步、实现Test01接口
class Test02 implements Test01{
@Override public void method() {
System.out.println("实现了Test接口的方法"); } }
//【使用匿名内部类】
public class Test {
public static void main(String[] args) {
//如果我们需要使用接口中的方法,我们只需要走一步,就是使用匿名内部类,直接将其类的对象创建出来。
new Test1(){
public void method(){
System.out.println("实现了Test接口的方法");
}
}.method();
}
}
interface Test1{
public void method(); }