Java内部类、泛型类和接口

Java内部类、泛型类和接口

本讲介绍Java面向对象的高级部分。对这一部分内容仅作必要而非深入的介绍。

 

一、Java内部类

在Java 语言中的类可以嵌套定义,允许在另外一个类中定义一个类,即在一个类的类体中可以嵌套(nested)定义另外一个类。外层的称为外部类(outer class),也可以叫做封闭类;内部的称为内部类(Inner Classes),有时也称为嵌套类(Nested Class)。内部类可以是静态(static)的,可以使用 public、protected 和 private 访问控制符,而外部类只能使用 public,或者默认。

 

例如:

class OuterClass {

    // code

    class InnerClass {

      // code

    }

}

 

Inner Classes 不能定义为static,不能有static方法和static初始化语句块。

内部类使用场景:当一个类只在某个类中使用,并且不允许除外部类外的其他类访问时,常用于GUI事件监听。

 

内部类的分类

☆成员式内部类

☆局部内部类

☆匿名内部类

 

有些人认为内部类的语法很复杂,实际开发中也较少用到,在此仅简要介绍。

 

成员式内部类

在外部类内部直接定义(不在方法内部或代码块内部)的类就是成员式内部类,它可以直接使用外部类的所有变量和方法,即使是 private 的。外部类要想访问内部类的成员变量和方法,则需要通过内部类的对象来获取。如:

public class Outer {

    private int size;

    public class Inner {

        private int counter = 10;

        public void doStuff() {

            size++;

        }

    }

    public static void main(String args[]) {

        Outer outer = new Outer();

        Inner inner = outer.new Inner();

        inner.doStuff();

        System.out.println(outer.size);

        System.out.println(inner.counter);

        // 下句编译错误,故注释掉,因为外部类不能访问内部类的变量

        //System.out.println(counter);

    }

}

输出:

1

10

 

注意:必须先有外部类的对象才能生成内部类的对象,因为内部类需要访问外部类中的成员变量,成员变量必须实例化才有意义。

 

成员式内部类如同外部类的一个普通成员。

 

成员式内部类可以使用各种修饰符,包括 public、protected、private、static、final 和 abstract,也可以不写。

 

若有 static 修饰符,就为类级,否则为对象级。类级可以通过外部类直接访问,对象级需要先生成外部的对象后才能访问。

 

非静态内部类中不能声明任何 static 成员。

 

内部类可以相互调用,例如:

class A {

    // B、C 间可以互相调用

    class B {}

    class C {}

}

 

局部内部类

局部内部类(Local class)是定义在代码块中的类。它们只在定义它们的代码块中是可见的。

局部类有几个重要特性:

仅在定义了它们的代码块中是可见的;

可以使用定义它们的代码块中的任何局部 final 变量;

局部类不可以是 static 的,里边也不能定义 static 成员;

局部类不可以用 public、private、protected 修饰,只能使用缺省的;

局部类可以是 abstract 的。

例子

public class OuterA {

    public static final int TOTAL_NUMBER = 5;

    public int id = 123;

    public void func() {

        final int age = 15;

        String str = "测试";

        class Inner {

            public void innerTest() {

                System.out.println(TOTAL_NUMBER);

                System.out.println(id);

                // System.out.println(str);不合法,只能访问本地方法的final变量

                System.out.println(age);

            }

        }

        new Inner().innerTest();

    }

    public static void main(String[] args) {

        OuterA OuterA = new OuterA();

        OuterA.func();

    }

}

运行结果:

5

123

15

 

匿名内部类

匿名内部类是局部内部类的一种特殊形式,也就是没有变量名指向这个类的实例,而且具体的类实现会写在这个内部类里面。

注意:匿名类必须继承一个父类或实现一个接口。

例子

abstract class PersonOne {

    public abstract void eat();

}

 

class Child extends PersonOne {

    public void eat() {

        System.out.println("eat something");

    }

}

 

public class DemoOne {

    public static void main(String[] args) {

        PersonOne p = new Child();

        p.eat();

    }

}

运行结果:

eat something

 

 

二、泛型类

所谓“泛型”,就是“宽泛的数据类型”,任意的数据类型。

假如我们现在要定义一个类来表示坐标,要求坐标的数据类型可以是整数、小数和字符串,例如:

x = 10、y = 10

x = 12.88、y = 129.65

x = "东京180度"、y = "北纬210度"

针对不同的数据类型,除了借助方法重载,还可以借助自动装箱和向上转型。我们知道,基本数据类型可以自动装箱,被转换成对应的包装类;Object 是所有类的祖先类,任何一个类的实例都可以向上转型为 Object 类型,例如: int --> Integer --> Object

还可以使用泛型类。

 

泛型类声明格式为:

class 类名<泛型列表>

如:class A<E,F>

其中,A是泛型类的名称,E、F是泛型类的参数,即泛型类的参数类型没有指定。它可以是任何引用类型,但不能是基本数据类型。

 

例子

public class DemoGeneric {

    public static void main(String[] args){

        // 实例化泛型类

        PointOne<Integer, Integer> p1 = new PointOne<Integer, Integer>();

        p1.setX(10);

        p1.setY(20);

        int x = p1.getX();

        int y = p1.getY();

        System.out.println("This Point is:" + x + ", " + y);

      

        PointOne<Double, String> p2 = new PointOne<Double, String>();

        p2.setX(25.4);

        p2.setY("东京180度");

        double m = p2.getX();

        String n = p2.getY();

        System.out.println("This Point is:" + m + ", " + n);

    }

}

 

// 定义泛型类

class PointOne<T1, T2>{

    T1 x;

    T2 y;

    public T1 getX() {

        return x;

    }

    public void setX(T1 x) {

        this.x = x;

    }

    public T2 getY() {

        return y;

    }

    public void setY(T2 y) {

        this.y = y;

    }

}

运行结果:

This point is:10, 20

This point is:25.4, 东京180度

 

上面的代码在类名后面多出了 <T1, T2>,T1, T2 是自定义的标识符,也是参数,用来传递数据的类型,而不是数据的值,我们称之为类型参数。在泛型中,不但数据的值可以通过参数传递,数据的类型也可以通过参数传递。T1, T2 只是数据类型的占位符,运行时会被替换为真正的数据类型。

 

传值参数(我们通常所说的参数)由小括号包围,如 (int x, double y),类型参数(泛型参数)由尖括号包围,多个参数由逗号分隔,如 <T> 或 <T, E>。

 

类型参数需要在类名后面给出。一旦给出了类型参数,就可以在类中使用了。类型参数必须是一个合法的标识符,习惯上使用单个大写字母,通常情况下,K 表示键,V 表示值,E 表示异常或错误,T 表示一般意义上的数据类型。

 

泛型类在实例化时必须指出具体的类型,也就是向类型参数传值,格式为:

className variable<dataType1, dataType2> = new className<dataType1, dataType2>();

 

注意:

泛型是 Java 1.5 的新增特性,它以C++模板为参照,本质是参数化类型(Parameterized Type)的应用。

类型参数只能用来表示引用类型,不能用来表示基本类型,如  int、double、char 等。但是传递基本类型不会报错,因为它们会自动装箱成对应的包装类。

 

 

三、Java接口(interface)

接口(Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。

接口就是比“抽象类"还“抽象”的“抽象类”, 可以更加规范的对子类进行约束。全面地专业地实现了:规范和具体实现的分离。接口是完全面向规范的,规定了一批类具有的公共方法规范。

从接口的实现者角度看,接口定义了可以向外部提供的服务。

从接口的调用者角度看,接口定义了实现者能提供那些服务。

接口是两个模块之间通信的标准,通信的规范。如果能把你要设计的模块之间的接口定义好,就相当于完成了系统的设计大纲,剩下的就是添砖加瓦的具体实现了。大家在工作以后,做系统时往往就是使用“面向接口”的思想来设计系统。

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

接口主要特点:

1、接口不能实例化对象 可以用来声明引用变量的类型

2、一个类实现一个接口,那么必须实现这个接口中定义的所有方法,并且只能是public

3、jdk1.7以及之前 接口中只能有方法的定义 jdk1.8之后可以有default(虚拟扩展方法)和静态方法

 

 

抽象类和接口的区别

接口

抽象类

不考虑java8default方法的情况下,接口中是没有实现代码的实现

抽象类中可以有普通成员方法 ,并且可以定义变量

接口中的方法修饰符号 只能是public

抽象类中的抽象方法可以有public,protected,default

接口中没有构造方法

可以有构造方法

 

接口和抽象类如何选择:

1、当我们需要一组规范的方法的时候,我们就可以用接口,在具体的业务中,来对接口进行实现,能达到以不变应对万变,多变的需求的情况我们只需要改变对应的实现类 。

2、如果多个实现类中有者相同可以复用的代码 这个时候就可以在实现类和接口之间,添加一个抽象类,把公共的代码抽出在抽象类中。然后要求不同实现过程的 子类可以重写抽象类中的方法,来完成各自的业务。

 

接口的定义(声明)语法格式如下:

[访问修饰符号] interface 接口名称 [extends 父接口1[,父接口2, ...]] {

       常量定义:

       方法定义:

}

访问修饰符:只能是public 或者默认

extends:接口支持多继承

接口中的属性只能是常量,默认就是public static finnal

接口中的方法默认是public abstract

换句话说,接口有以下特性:

接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。

接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键子。

接口中的方法都是公有的。

一个接口,可以拥有N个直接的父接口,如:

interface A

{

  …

}

interface B

{

  …

}

interface C

{

  …

}

//一个接口,可以拥有N个直接的父接口

public interface D extends A,B,C

{

  …

}

 

 

接口的实现

当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。

使用implements关键字实现接口,接口实现的语法:

类修饰符 class 类名称 implements 接口名称1[, 接口名称2, ...] {

  ...

}

 

下面给出一个例子,代码如下:

//用interface声明两个接口

interface Person {

       void say();

}

interface Parent {

       void work();

}

//用implements实现两个接口

class Child implements Person, Parent {

       public void work() {

              System.out.println("学习");

       }

       public void say() {

              System.out.println("Child");

       }

}

public class TestImplements{

       public static void main(String[] args) {

              Child c = new Child();

              c.say();

              c.work();

       }

}

 

运行输出结果:

Child

学习

 

下面再给出一个例子,代码如下:

//创建一个接口名字为Abc

interface Abc {

        //创建接口方法getMax

        public int getMax();

        //创建接口方法getMes

        public String  getMes();

}

 

 

//test2类描述的是实现接口的方法

class test2 implements Abc{

        //实现接口里的方法

        public int getMax()

        {

               //定义int类型的私有变量i

               int i = 123;

                //将变量i返回出去并退出方法

               return i;

        }

 

        //实现接口里的方法

        public String getMes()

        {

               //定义String类型的私有变量s

               String s = "实现接口里的方法";

                //将变量s返回出去并退出方法

               return s;

        }

 

}

public class TestImplements2{     

       

        //main方法为Java程序的入口方法

        public static void main(String args[])

        {

                //创建test类的对象实例,引用为t

                test2 t = new test2();

               

                //实现了接口里的方法并进行调用

               int i = t.getMax();

               String s = t.getMes();

               

               //打印并显示结果

               System.out.println(i);

               System.out.println(s);

        }

}

运行输出结果:

123

实现接口里的方法

 

 

 

猜你喜欢

转载自blog.csdn.net/cnds123/article/details/111923410
今日推荐