Java内部类、抽象类、泛型和接口

您所在的位置:网站首页 泛型抽象类 Java内部类、抽象类、泛型和接口

Java内部类、抽象类、泛型和接口

2024-07-16 05:37| 来源: 网络整理| 查看: 265

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

Java内部类更多介绍,可参见 https://blog.csdn.net/cnds123/article/details/130627538

二、抽象类

java语言中,用abstract 关键字来修饰一个类时,这个类叫作抽象类。

普通类是一个完善的功能类,可以直接产生实例化对象,并且在普通类中可以包含有构造方法,普通方法,static方法,常量和变量等内容。而抽象类除了含有普通类的成员,必须含有抽象方法。

那么什么叫抽象方法呢?在所有的普通方法上面都会有一个"{}",这个表示方法体,有方法体的方法一定可以被对象直接使用。而抽象方法,是指,没有方法体的方法,且抽象方法必须被abstract关键字所修饰。

拥有抽象方法体的类就被成为抽象类,抽象类必须使用abstract关键字所修饰,如果一个类包含抽象方法,所以该类必须是抽象类。注意:抽象类不一定有抽象方法,但是有抽象方法的类必须定义成抽象方法。

抽象类的定义使用abstract关键字,抽象方法也使用abstract关键字进行修饰。如果一个类包含抽象方法,则该类必须声明为抽象类。

下面给出一个简单示例源码:

abstract class AnimalsDemo{

    String name = "猫咪";

    abstract void eat();

}

class Cats extends AnimalsDemo{

    @Override

    void eat() {

        System.out.println(name + "正在吃饭");

    }

}

public class TestB {

    public static void main(String[] args) {

        Cats cats = new Cats();

        cats.eat(); //猫咪正在吃饭

    }

}

抽象类不能创建对象,如果硬要创建,会出现编译报错。

抽象类中,可以有构造方法,是供子类创建对象时,初始化父类使用的。

抽象类中不一定包含抽象方法,但是有抽象方法的类一定是抽象类,不包含抽象方法的抽象类,目的就是不想让调用者实例化该对象,通常用于某些特殊的类的结构设计。

抽象类的子类,必须重写抽象父类的所有抽象方法,否则会出现编译报错,除非该子类也是抽象类(假设不重写父类中所有的抽象方法,那么调用抽象方法毫无意义)。

Java中的抽象类更多介绍,可参见 https://blog.csdn.net/cnds123/article/details/130618011

三、泛型

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

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

x = 10、y = 10

x = 12.88、y = 129.65

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

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

还可以使用泛型类。

泛型类声明格式为:

class 类名

如:class A

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

例子

public class DemoGeneric {

    public static void main(String[] args){

        // 实例化泛型类

        PointOne p1 = new PointOne();

        p1.setX(10);

        p1.setY(20);

        int x = p1.getX();

        int y = p1.getY();

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

      

        PointOne p2 = new PointOne();

        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 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 只是数据类型的占位符,运行时会被替换为真正的数据类型。

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

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

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

className variable = new className();

注意:

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

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

Java中的泛型更多介绍,可参见 https://blog.csdn.net/cnds123/article/details/130605741

四、Java接口(interface)

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

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

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

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

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

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

接口主要特点:

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

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

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

抽象类和接口的区别

接口

抽象类

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

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

接口中的方法修饰符号 只能是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

实现接口里的方法

Java接口更多介绍,可参见 https://blog.csdn.net/cnds123/article/details/130618885



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3