• Java学习笔记————泛型程序设计


    1.  泛型程序设计

    1.1      泛型的引出

    要求设计一个可以表示坐标的类(X,Y)但是此坐标要可以同时满足以下三种集中要求:

    ·X=10、Y=100        ·X=10.3、Y=50.2     ·X=”东经180°”、Y=”北纬210°”

    分析:

    因为现在的程序中需要接受三种数据类型的数据,所以呢为了保证程序的正确性,最好使用Object类完成,因为Object可以接受任意的引用数据类型:

    ·数字 à 自动装箱操作 à Object       ·字符串 à Object

    按照以上的特点,完成程序:

    class Point {

        private Object x;

        private Object y;

        public Object getX() {

            return x;

        }

        public void setX(Object x) {

            this.x = x;

        }

        public Object getY() {

            return y;

        }

        public void setY(Object y) {

            this.y = y;

        }

    }

    此时Point类完成了,那么设置一个整形数字,来观察是否可以操作。

    public class GenDemo01 {

        public static void main(String[] args) {

            Point p = new Point();

            p.setX(10); // 设置坐标。int --> Integer --> Object

            p.setY(10);// 设置坐标。int --> Integer --> Object

            int x = (Integer)p.getX() ; // 取出X:Object --> Integer --> int

            int y = (Integer)p.getY() ; // 取出X:Object --> Float --> float

            System.out.println("x = " + x);

            System.out.println("y = " + y);

        }

    }

    下面继续完成设置小数的操作:

    public class GenDemo02 {

        public static void main(String[] args) {

            Point p = new Point();

            p.setX(10.3f); // 设置坐标。float --> Float --> Object

            p.setY(10.6f);// 设置坐标。float --> Float --> Object

            float x = (Float)p.getX() ; // 取出X:Object --> Float --> float

            float y = (Float)p.getY() ; // 取出X:Object --> Float --> float

            System.out.println("x = " + x);

            System.out.println("y = " + y);

        }

    }

    下面继续设置字符串最为X和Y的坐标:

    public class GenDemo03 {

        public static void main(String[] args) {

            Point p = new Point();

            p.setX("东经120度"); // 设置坐标。String --> Object

            p.setY("北纬230度");// 设置坐标。String --> Object

            String x = (String)p.getX() ;   // 取出X:Object --> String

            String y = (String)p.getY() ;   // 取出X:Object --> String

            System.out.println("x = " + x);

            System.out.println("y = " + y);

        }

    }

    此时基本点的功能已经完成了,但是此种操作是否存在问题呢???

    在此操作之中,可以发现所有的内容都是Object进行操作的,那么就意味着,可以设置任意的类型,即:X可以使整型,Y可以使字符串类型。

    public class GenDemo04 {

        public static void main(String[] args) {

            Point p = new Point();

            p.setX(10); // 设置坐标。int --> Integer --> Object

            p.setY("北纬230度");// 设置坐标。int --> Integer --> Object

            int x = (Integer)p.getX() ; // 取出X:Object --> Integer --> int

            int y = (Integer)p.getY() ; // 取出X:Object --> Float --> float

            System.out.println("x = " + x);

            System.out.println("y = " + y);

        }

    }

    此时程序编译的时候不存在任何问题,但是在执行的时候却出现了以下异常。

    Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

        at com.java.genericsdemo01.GenDemo04.main(GenDemo04.java:20)

    之所以会这样,是因为在程序中所有的属性都可以向Object进行转换,那么,此程序的入口就显得不那么规范了,而且存在安全漏洞。

    但是从之前所学过的全部代码来看,此处孩子能应用到这里了。没有更好的方法了

    1.2      泛型<1>基础知识

    JDK 1.5 之后出现了新的技术 —— 泛型,此技术的最大特点就是类中的属性的类型可以由外部决定,而且声明的时候应该采取如下形式:

    class 类名称 <泛型类型,泛型类型,……>{

    }

    那么现在采用如上的格式来修之前的操作。

    package com.java.genericsdemo02;

    public class Point<T> { // 表示坐标类

        private T x;    //  X 的属性类型有外部决定

        private T y;    //  Y 的属性类型由外部决定

        public T getX() {

            return x;

        }

        public void setX(T x) {

            this.x = x;

        }

        public T getY() {

            return y;

        }

        public void setY(T y) {

            this.y = y;

        }

    }

    此时,程序中加入了泛型之后,可以发现一切操作类型都不在由程序固定设置。而是在实例化对象的时候在外部进行了指定。

    package com.java.genericsdemo02;

    public class GenDemo05 {

        public static void main(String[] args) {

            Point<Integer> p = new Point<Integer>();

            p.setX(10); // 设置坐标。int --> Integer --> Object

            p.setY(20);// 设置坐标。int --> Integer --> Object

            System.out.println("x = " + p.getX());

            System.out.println("y = " + p.getY());

        }

    }

    发现此时在使用Point类的时候,需要加入一个属性类型的声明。而且加入之后再取出属性值的时候本身也变得非常容易,不需要再使用向下转型了。

    而且,使用上面的操作有一点点最方便之处,如果此时设置的内容不是整型,那么程序中将出现错误。

    package com.java.genericsdemo02;

    public class GenDemo06 {

        public static void main(String[] args) {

            Point<Integer> p = new Point<Integer>();

            p.setX(10); // 设置坐标。int --> Integer --> Object

            p.setY[1]("北纬230度");// 设置坐标。int --> Integer --> Object

            System.out.println("x = " + p.getX());

            System.out.println("y = " + p.getY());

        }

    }

    加入泛型之后可以对程序的操作起到更加安全的目的.

    1.3      泛型<2>注意点

    在使用泛型操作的时候,实际上有很多小的注意点,例如:构造方法上依然可以使用泛型或者有一种可以成为泛型的擦除。

    1.3.1        在构造方法上引用泛型

    一般在开发中,经常使用造方法设置属性的内容,那么此时实际上依然可以使用泛型的类型。

    package com.java.demo03;

    public class Point<T> {

        private T x;

        private T y;

        public Point(T x, T y) {

            this.setX(x);

            this.setY(y);

        }

        public T getX() {

            return x;

        }

        public void setX(T x) {

            this.x = x;

        }

        public T getY() {

            return y;

        }

        public void setY(T y) {

            this.y = y;

        }

    }

    那么此时在调用的时候就需要使用构造方法设置内容,当然,设置的内容依然由泛型本身决定。

    package com.java.demo03;

    public class GenDemo07 {

        public static void main(String[] args) {

            Point<Integer> p = new Point<Integer>(10, 20);

            int x = p.getX();

            int y = p.getY();

            System.out.println("x = " + x);

            System.out.println("y = " + y);

        }

    }

    1.3.2        擦除泛型

    如果在使用的时候没有指定泛型类型的话,则表示擦除泛型类型。

    泛型一旦擦除之后,就按照Object进行接收,以保证程序不发生任何错误。

    package com.java.demo03;

    public class GenDemo08 {

        public static void main(String[] args) {

            Point p = new Point(10, 20);

            int x = (Integer) p.getX();

            int y = (Integer) p.getY();

            System.out.println("x = " + x);

            System.out.println("y = " + y);

        }

    }

    但是在以上的操作代码中,依然会存在警告信息。那么应该如何去掉警告信息呢???

    package com.java.demo03;

    public class GenDemo08 {

        public static void main(String[] args) {

            Point<Object> p = new Point<Object>(10, 20);

            int x = (Integer) p.getX();

            int y = (Integer) p.getY();

            System.out.println("x = " + x);

            System.out.println("y = " + y);

        }

    }

    但是,以上的操作虽然去掉了警告信息,但是有些多余,建议在开发者一般不要擦除泛型。

    1.4      通配符

    在泛型的操作中通配符的使用较多,而且在日后的系统类库中有很多地方都要使用这些操作

    例如,现在又如下代码:

    package com.java.demo04;

    public class Test {

        public static void main(String[] args) {

            Object obj ="Hello World!!!";

        }

    }

    以上的语法实际上是进行了向上的转型,因为String 是 Object的子类,但是在泛型中却没有此概念。

    1.4.1        ?

    在进行对象转型的时候可以使用自动的向上转型,但是在使用泛型的时候却没有此种操作。

    package com.java.demo04;

    public class Point<T> {

        private T x;

        private T y;

        public T getX() {

            return x;

        }

        public void setX(T x) {

            this.x = x;

        }

        public T getY() {

            return y;

        }

        public void setY(T y) {

            this.y = y;

        }

    }

    那么下面定义两个Point类的对象。

    package com.java.demo04;

    public class GenDemo09 {

        public static void main(String[] args) {

            Point<Object> p1 = new Point<Object>();

            Point<Integer> p2 = new Point<Integer>();

            p1 = p2;    //  此时根本无法进行转换。

        }

    }

    此时的程序根本就无法进行转换的操作,此时程序实际上就已经不完全属于对象转换操作了,而属于一个大的类型和小的类型划分。

    例如:将“Point<Object> p1 = new Point<Object>();”表示为商场的全部商品,而“Point<Integer> p2 = new Point<Integer>();”表示每一个顾客购买的商品,如果现在执行“p1 = p2;”那么就意味着,此顾客所购买的商品就是商场的全部商品,这样肯定说不通,所以说不能接收。

    不能使用以上的方式接收最大的影响在于方法的参数接收。

    package com.java.demo04;

    public class GenDemo10 {

        public static void main(String[] args) {

            Point<Object> p1 = new Point<Object>();

            Point<Integer> p2 = new Point<Integer>();

            fun(p1);

            fun(p2);

        }

        public static void fun(Point point){    //  表示此时可以接受任意的类型。

            System.out.println(point.getX());

            System.out.println(point.getY());

        }

    }

    此时程序可以正常编译运行,但是“fun(Point point)”处会出现警告信息,现在不想让其出现警告信息,那么可以进行以下操作:

    package com.java.demo04;

    public class GenDemo10 {

        public static void main(String[] args) {

            Point<Object> p1 = new Point<Object>();

            Point<Integer> p2 = new Point<Integer>();

            fun(p1);

            fun(p2);

        }

        public static void fun(Point<?> point){ //  表示此时可以接受任意的类型。

            System.out.println(point.getX());

            System.out.println(point.getY());

        }

    }

    程序中的“?”表示可以接收任意类型的泛型类型,但是只能是接收和输出,并不能修改。

    1.4.2        泛型的上限

    上限就是指一个操作泛型的最大的操作父类,例如,现在最大的上限设置成“Number”那么此时,所能够就收的类型只能是Number及其子类(Integer)。

    泛型上限通过以下语法完成:

    ? extends 类

    例如:在Point类中只能设置数字类型的坐标。

    package com.java.demo05;

    public class Point<T extends Number> {  //  最高只能是Number类型。

        private T x;

        private T y;

        public T getX() {

            return x;

        }

        public void setX(T x) {

            this.x = x;

        }

        public T getY() {

            return y;

        }

        public void setY(T y) {

            this.y = y;

        }

    }

    以上的泛型类型明确的指出,最大的操作父类是Number,设置的内容只能是Integer、Float等等。

    package com.java.demo05;

    public class GemDemo11 {

        public static void main(String[] args) {

            Point<Integer> p1 = new Point<Integer>();   //  设置的是Number的子类。

        }

    }

    如果此时设置的泛型类型是字符串的话,则也会出现错误。

    package com.java.demo05;

    public class GemDemo12 {

        public static void main(String[] args) {

            Point<String> p1 = new Point<String>(); //  设置的是Number的子类。

        }

    }

    Bound mismatch: The type String is not a valid substitute for the bounded parameter <T extends Number> of the type Point<T>

    而且泛型上限也可以在方法上使用,例如,接收参数:

    package com.java.demo05;

    public class GenDemo13 {

        public static void main(String[] args) {

            Point<Integer> p2 = new Point<Integer>();

            fun(p2);

        }

        public static void fun(Point<? extends Number> point){  //此时可以接受Number的子类。

            System.out.println(point.getX());

            System.out.println(point.getY());

        }

    }

    1.4.3        泛型的下限

    泛型的下限指的是只能设置其具体的类或者父类,设置语法如下:

    ? super 类

    例如,定义一个方法,此方法之鞥接收String或Object类型的泛型对象。

    package com.java.demo06;

    public class Point<T> {

        private T x;

        private T y;

        public T getX() {

            return x;

        }

        public void setX(T x) {

            this.x = x;

        }

        public T getY() {

            return y;

        }

        public void setY(T y) {

            this.y = y;

        }

    }

    在方法中设置泛型的下限:

    package com.java.demo06;

    public class GenDemo14 {

        public static void main(String[] args) {

            Point<String> p1 = new Point<String>();

            Point<Object> p2 = new Point<Object>();

            fun(p1);

            fun(p2);

        }

        public static void fun(Point<? super String> point){

            System.out.println(point.getX());

            System.out.println(point.getY());

        }

    }

    1.5      泛型接口

    泛型不管可以在类上使用,还可以在接口中进行定义。操作的语法如下:

    Interface 类口名称<泛型类型,泛型类型,…>{}

    范例:定义泛型接口:

    package com.java.demo07;

    public interface Demo<T> {  //  定义泛型接口。

        public void print(T param); //  此抽象方法中使用了泛型类型

    }

    泛型接口定义完成之后,下面就需要定义类是吸纳接口,实现的方法有两种:

    范例:第一种实现手段

    package com.java.demo07;

    public class DemoImpl01<T> implements Demo<T> {

        public void print(T param) {

            System.out.println("Param = " + param);

        }

    }

    下面对以上的程序进行测试:

    package com.java.demo07;

    public class GenDemo15 {

        public static void main(String[] args) {

            Demo<String> demo = new DemoImpl01<String>();

            demo.print("Hello");

        }

    }

    范例:第二种做法(设置具体类型)

    package com.java.demo07;

    public class DemoImpl02 implements Demo<DemoImpl02> {   //  设置具体类型

        public void print(DemoImpl02 param) {

            System.out.println("Param = " + param);

        }

    }

    此时print方法中只能接收DemoImpl02实例对象

    package com.java.demo07;

    public class GenDemo16 {

        public static void main(String[] args) {

            Demo<DemoImpl02> demo = new DemoImpl02();

            demo.print(new DemoImpl02());

        }

    }

    1.6      泛型方法

    泛型除了可以再类中定义之外,还可以在方法中定义,而且在方法上使用泛型,此方法所在的类不一定是泛型的操作。

    package com.java.demo08;

    public class Demo {

        public <T> T print(T param){    //  定义泛型方法

            return param;

        }

    }

    Demo类中print()方法可以接收泛型类型,而且此方法的返回值也是指定的泛型类型,下面使用以上的类进行操作。

    package com.java.demo08;

    public class GenDemo17 {

        public static void main(String[] args) {

            Demo demo = new Demo();

            System.out.println(demo.print(1));

        }

    }

    当然也可以将方法的返回值定义成一个泛型的数组。

    package com.java.demo08;

    public class GenDemo18 {

        public static void main(String[] args) {

            Integer i[] = fun(1, 2, 3, 4, 5, 6, 7, 8, 9);

            for(int x : i){

                System.out.print(x + "\t");

            }

        }

        public static <T> T[] fun(T... param) {

            return param;   //  返回数组

        }

    }

    1.7      泛型的嵌套操作

    现在只是突出语法,具体操作的意义要等到后面学习到类库才能够更加明白。

    package com.java.demo09;

    public class Info<T> {

        private T param;

        public T getParam() {

            return param;

        }

        public void setParam(T param) {

            this.param = param;

        }

    }

    之后再定义一个Person类

    package com.java.demo09;

    public class Person<T> {

        private T info;

        public T getInfo() {

            return info;

        }

        public void setInfo(T info) {

            this.info = info;

        }

    }

    此时如果要将Info的类型设置到Person中,那么同时既要指定Person的泛型类型,又要指定Info中的泛型类型。

    package com.java.demo09;

    public class Test {

        public static void main(String[] args) {

            Person<Info<String>> person = new Person<Info<String>>();

            person.setInfo(new Info<String>());

            person.getInfo().setParam("Hello World!!!");

            System.out.println(person.getInfo().getParam());

        }

    }

    这就是泛型的嵌套的设置,以上的在后面将会有所应用。

    1.8      泛型的操作范例

    现在有如下的题目要求:

    要求设计一个程序,定义一个Person类,Person类中药存放具体的信息,但是信息分为基本信息或者联系方式等等,那么此时该如何设计呢?

    此时最好的设计就是需要定义一个好事信息的操作标准,但是此时这个标准肯定使用接口实现,但是现在接口中并不编写任何的操作。

    package com.java.demo10;

    public interface Info {

    }

    接口中没有任何操作代码,所以,此种接口在设计上称为标示接口,标示一种能力。之后定义Person类,Person类中的信息只能由Info的子类决定,所以此时指定了上限。

    package com.java.demo10;

    public class Person<T extends Info> {

        private T info;

        public T getInfo() {

            return info;

        }

        public void setInfo(T info) {

            this.info = info;

        }

    }

    以上的操作类中,能够设置的内容只能是Info的子类.

    package com.java.demo10;

    public class Basic implements Info {

        private String name;

        private int age;

        public Basic() {

            super();

        }

        public Basic(String name, int age) {

            super();

            this.name = name;

            this.age = age;

        }

        public String getName() {

            return name;

        }

        public void setName(String name) {

            this.name = name;

        }

        public int getAge() {

            return age;

        }

        public void setAge(int age) {

            this.age = age;

        }

        public String toString() {

            return "人的信息:" + "\n\t|-姓名:" + this.getName() + "\n\t|-年龄:" + this.getAge();

        }

    }

    以上只是基本信息,但是在人中还有联系方式的子类.

    package com.java.demo10;

    public class Contact implements Info {

        private String address;

        private String zipcode;

        public Contact() {

            super();

        }

        public Contact(String address, String zipcode) {

            super();

            this.address = address;

            this.zipcode = zipcode;

        }

        public String getAddress() {

            return address;

        }

        public void setAddress(String address) {

            this.address = address;

        }

        public String getZipcode() {

            return zipcode;

        }

        public void setZipcode(String zipcode) {

            this.zipcode = zipcode;

        }

        public String toString() {

            return "联系信息:" + "\n\t|-家庭住址:" + this.getAddress() + "\n\t|-邮政编码:"

                    + this.getZipcode();

        }

    }

    下面使用基本信息完成操作:

    package com.java.demo10;

    public class TestPerson01 {

        public static void main(String[] args) {

            Person<Basic> person = new Person<Basic>();

            person.setInfo(new Basic("张三", 30));

            System.out.println(person.getInfo());

        }

    }

    下面使用地址信息完成操作:

    package com.java.demo10;

    public class TestPerson02 {

        public static void main(String[] args) {

            Person<Contact> person = new Person<Contact>();

            person.setInfo(new Contact("开封市", "475001"));

            System.out.println(person.getInfo());

        }

    }

    以上Person中的信息只能是Info的子类,从而保证了操作的正确性.



    [1] 下划线表示有错误出现

  • 相关阅读:
    树7:给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。
    树6:请实现两个函数,分别用来序列化和反序列化二叉树 。
    树5:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。
    树3:请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的
    树2:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
    树1:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
    3在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
    WPF 利用RichTextBox 打印出不同颜色的文本
    VS生成后,产生roslyn目录
    CancellationTokenSource
  • 原文地址:https://www.cnblogs.com/zhangtingkuo/p/2785002.html
Copyright © 2020-2023  润新知