java中接口是一个很重要的知识板块,同学们有不理解的地方可以看一下本篇文章,本篇文章将介绍接口与静态内部类和匿名内部类。
一、接口
java中引用类型有:数组,String,类,接口。今天我们介绍一下接口:
1、接口基础介绍
定义的语法:interface + 接口名{}
成员方法:接口内的方法默认是抽象方法,所以不能具体实现,如果想实现的话需要用default或者static修饰方法
成员变量:默认是由public static final修饰
接口是不能被实例化的
类与接口的关系:类+implements+接口用来实现接口,接口内的方法由于是抽象方法,所以实现接口的类必须重写方法。类可以继承一个抽象类/类的同时实现接口。
接口与接口的关系:接口+extends+接口用于继承接口(可以继承多个接口)。
结合上面的基础知识,我们可以来写一个实验实践:
interface Ifly{
void fly(); //会飞的动作,建立fly接口
}
interface Irun{
void run(); //并不是所有动物都会跑会飞,如果都写成类会造成类只能一个类的问题
}
interface Iswim{
void swim(); //比如说狗会跑会游泳,写成类的话只能继承其中一个
}
abstract class Animal{
public String name;
public int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public abstract void eat(); //动物都会吃,所以建立eat抽象方法
}
class Dog extends Animal implements Irun,Iswim{
@Override
public void run() { //继承抽象类,实现接口后都要重写方法
System.out.println("wangcai正在跑");
}
@Override
public void swim() {
System.out.println("wangcai正在游泳");
}
public Dog(String name, int age) {
super(name, age); //继承父类记得构造父类的构造方法
}
@Override
public void eat() {
System.out.println("wangcai正在吃狗粮");
}
}
class Duck extends Animal implements Ifly,Iswim{
public Duck(String name, int age) {
super(name, age);
}
@Override
public void eat() {
System.out.println("yaya正在吃鸭粮");
}
@Override
public void fly() {
System.out.println("yaya正在飞");
}
@Override
public void swim() {
System.out.println("yaya正在游泳");
}
}
public class Test {
public static void testFly(Ifly ifly){
ifly.fly(); //通过传参的方式进行动态绑定
}
public static void testSwim(Iswim iswim){
iswim.swim(); //形参iswim调用的方法只有实现Iswim接口的类可以调用
}
public static void testRun(Irun irun){
irun.run(); //因此就算一个类不继承Animal,也能调用实现的接口,这点会使程序员忘记类
}
public static void main(String[] args) {
testFly(new Duck("yaya",2)); //建立动态绑定,实现接口的方法
testRun(new Dog("wangcai",3)); //创建Irun接口时建立了抽象方法run,就是为了子类继承并重写,以此达到动态绑定
}
}
接口与抽象类的区别:抽象类中可以有和普通类一样的成员变量和成员方法,但接口中的变量只能是public static final的,方法只能是public abstra的;类只能继承一个抽象类,但可以实现多个接口,解决了java中不能继承多个类的问题。
2、Object类
object是所有类的父类,意味着可以发生向上转型及动态绑定,双击shift然后搜索object类可以得到这个类的所有方法
举例:当我们写出这样一个字段
public class Test1 {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
}
class Person{
public String name = "xiaohong";
}
我们想要在主函数打印person的名字xiaohong,但输出结果为
并不是我们想要的结果,所以我们点进println的源码查看
发现是父类Object来接收我们传的person类,这是传参方法的向上转型,我们可以看到接收之后形参传给了value of方法,接着我们点进这个方法的源码
同样也是向上转型,Object来接收,return后意为obj是否为空,为空时返回null,不为空时返回Obj的toString方法,接着我们点进toString的源码这就是我们print person返回哈希值的罪魁祸首,所以要想返回出我们想要的name名,只需子类重写这个方法,这样我们调用print方法时就会发生动态转移,从而调用子类我们重写的方法
class Person{
public String name = "xiaohong";
@Override
public String toString() {
return "name:"+name;
}
}
输出结果为
别的方法同理,根据实例情况来重写obj方法实现自己的需求。
二、内部类
在一个事物的内部,还有一部分需要一个完整的结构描述,而这个内部的完整结构又只为外部事物提供服务,此时建议使用内部类。
在java中,可以将一个类定义在一个类或一个方法的内部,前者称为内部类后者称为外部类。内部类也能体现封装的思想。
内部类分为:
1、静态内部类:被static修饰的内部成员类
public static void main(String[] args) {
OuterClass.InnerClass innerClass = new OuterClass.InnerClass();
//调用静态内部类的语法
innerClass.test();
}
class OuterClass{
static int a = 1;
private static int b = 2;
static class InnerClass{
public int c = 3;
public static int d = 4;
public void test(){
System.out.println();
System.out.println(OuterClass.a); //内部类不能直接调用外部类的非静态成员变量 非要调用需要使用外部类名+.变量名访问
System.out.println(b); //内部类可以直接访问外部静态成员变量
System.out.println(c); //内部类的成员变量直接访问即可
System.out.println(d); //内部的静态成员也是
}
}
}
内部类不能直接访问外部类成员是因为:外部类成员依赖外部类对象,不实例化对象无法访问成员变量,所以使用类名来访问。
2、实例内部类
就是不加static的内部类,实例内部类可以当作外部类的一个实例内部类,外部类的方法在调用时需要使用外部类创建的对象来进行调用,因此调用实例内部类的也需要外部类对象进行引用
public static void main(String[] args) {
OuterClass.InnerClass innerClass1 = new OuterClass().new InnerClass();
innerClass1.test();
}
class OuterClass{
static int a = 1;
private static int b = 2;
class InnerClass{
public int c = 3;
public void test(){
System.out.println("实现实例内部类");
}
}
}
需要注意的是,由于是实例内部类也是依赖对象的,所以实力内部类不能使用不依赖对象的static关键字,如果非要使用的话,需要加final变成常量。
3、匿名内部类
public static void main(String[] args) {
Ia ia = new Ia(){
@Override
public void func() {
System.out.println("重写了接口的方法");
} //这就是匿名内部类,重写了接口的方法
};
}
interface Ia{
void func();
}
class testInner implements Ia{
@Override
public void func() {
System.out.println("实现匿名内部类");
}
}
接口的引用引用了匿名内部类,想引用匿名内部类不是一定需要接口的引用,类的对象的引用也可以。