服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - Java泛型枚举Annotation接口详细解读与Eclipse发展

Java泛型枚举Annotation接口详细解读与Eclipse发展

2021-11-30 11:54zsr6135 Java教程

这篇文章主要给大家介绍了关于Java中方法使用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

1、Eclipse开发工具

1.1 Eclipse历史

Eclipse中文翻译为日蚀,指的是吞没一切的光芒,那么这个及其具备挑衅一位的名字实际上是针对于SU年公司。在2000年之后一直处于互联网低潮,而SUN公司从这一低潮之后就再也没有起来过,而后SUN公司最为尴尬的是,他在硬件上没有过多的收益,而且软件的编程语言Java也不是SUN的赚钱工具,它只是变成了一个出卖版权的公司了。

对于Java的IDE(集成开发环境)本身也是经过了一些历史的调整。

​ 1995年的时候,Java诞生,但是SUN公司却高调宣布,我们自己不生成IDE,给其他第三方公司生产;

​ 在Java产生之后,Borland公司来时入手Java的IDE生产,所以后来的JBuilder就成为了Java开发的唯一选择(不选择JBuilder都使用记事本,IDEA,JCREATOR,EDIPLUS….),后俩一直到了JBuilderX之后才正常;

​ 2003年之后有了Eclipse,在2004年之后有了SUN自己的开发工具———NetBeans

而从整个国内的Java开发模式上也一直在发生着改变;

​ 豪华级架构:操作系统+数据库+中间件+开发工具+编程语言;

​ IBM体系:AIX+IBM DB2+WwbsphereApplicationServer+WSAD;

​ 超级杂牌军体系:UNIX+Oracle+Weblogic+JBuilder;

免费架构:Linux+MySQL+Tomcat/JBoss+Eclipse;

而对于开发工具最早的霸主就是JBuilder,但是遗憾的是,2006年的时候Borland倒闭了,倒闭的原因是因为没有干声多为的开源风潮,因为有许多的学习者,它可能并不需要如此专业的工具,所以当时Borland公司的市场就出现了问题,于是倒闭就成为了必然,最后Borland技术部单独成立了一家技术公司,继续从事JBuilder的研究,但是今天的JBuilder已经基本上无法去问津了,完全被Eclipse取代了。

Eclipse是由IBM开发的,之后将其转送给了今天的Eclipse组织,进行开源项目的推广,而Eclipse的前身是IBM VisualAge,而后IBM根据Eclipse的1.0模型,产生后来的WSAD来发工具。Eclipse本身是免费的,但是其是靠插件收费(中国连插件都不需要收费),其本身有一下几个基本组成:JDT,JUNIT测试工具,CVS客户端,插件开发,用户可以直接登陆www.eclipse.org下载Eclipse的最新版本,JUNO(朱诺,小行星的名字)版,而且Eclipse现在可以直接解压缩后使用,不用单独的安装,是纯粹的绿色版。

当我们Java项目简历完成值周,可以在项目的目录小发现两个文件夹:

​ Src:是保存所有的*.java程序,都是按照包名称进行保存的;

​ Bin:保存所有生成的*.class文件,按照包名称进行保存的。

下面简历一个新的类:TestDemo.java

使用Eclipse本身最大的好处在于方便的进行随笔提示,并且在每一次*.java程序保存的时候,会由Eclipse自动的将其编译为*.class文件。

另外在Eclipse之中还可以存在一些代码生成工具,例如:现在有如下简单类

?
1
2
3
4
5
6
package com.sxau;
 
public class Person {
    private String name;
    private int age;
}

这个类肯定是作为简单Java类出现,那么现在很明显简单Java类的开发原则:

所有属性封装,已经封装;生成setter,getter方法;构造方法,必须要有无参构造覆写Object中的一些方法

1.2 快捷键

除了以上的生成方式还可以通过快捷键生成

ALT+/:代码自动补充提示;CTRL+1:进行错误代码矫正提示;CTRL+D:删除当前行代码;CTRL+SHIFT+O:自动导入包;CTRL+SHIFT+F:格式化代码显示;CTRL+/:注释/取消注释;CTRL+shift+l:快捷键列表CTRL+H:搜索

项目也可以进行删除操作,但是在删除项目的时候有两种方式:

​ 方式一:是从项目的工作区之中删除,以后可以恢复;

​ 方式二:彻底从硬盘上删除项目。

如果想导入项目则可以使用导入的方式。

​ 以上是利用导入的方式完成了项目的导入,而现在也可以通过导出的方式,将一个项目之中的所有*.class文件自动生成*.jar文件。

1.3 Debug调试

在Eclipse之中,为了方便永华的开发,还提供了DEBUG功能,可以利用此功能进行项目的调试操作,而如果要想进行调试,首先需要设置断点。断点指的是程序执行到此处的时候,自动停止,而后交给人工控制执行。

**范例:**设置断点

?
1
2
3
4
5
6
7
8
9
10
package com.util;
 
public class MyMath {
    private MyMath(){}
    public static int add(int x, int y){
        int temp = 0;
        temp = x + y;
        return temp;
    }
}

测试类

?
1
2
3
4
5
6
7
8
9
10
11
package com.test;
 
import com.util.MyMath;
 
public class TestMath {
    public static void main(String[] args) {
        int result = MyMath.add(2, 3);//将此处设置为断电
        System.out.println("加法结果" +  result);
    }
    
}

Java泛型枚举Annotation接口详细解读与Eclipse发展

进入调试试图之后可以通过以下方式进行代码调试:

  1. 单步跳入(F5):进入到代码之中观察代码的执行;
  2. 单步跳过(F6):不关心代码之中的执行,只关心最终的结果;
  3. 单步返回(F7):返回到单步跳过的状态
  4. 恢复执行(F8):不再调试直接将程序运行完成。

1.4 JUNIT测试工具

软件测试行业:2003年——2006年之后,各个公司一直都在招聘软件测试人员,而且都是外包到IBM或微软的公司进行测试。但是,今天的软件测试来讲,这个行业已经很难了。

软件测试是一个黄金职位,对于软件测试是需要有一套完整测试理论和数据设计的,而如果学习过软件工程应该知道软件测试分为两类:

​ 1 黑盒测试:主要是测试功能,例如一些xx版,是不接触代码的,但是公司会提供工具;

​ 2 白盒测试:指的是性能测试,或者是算法调整。

而这几年随着行业的发展,实际上又给出了一种新的测试职位——Use Case(用测)测试工程师,对于这种职位而言,国内的平均待遇是程序员的3-5倍,如果按照正常的一个程序员的工资是8000来算,那么这种人的平均工资就是2-5万,但是人很难难找,一般而言此类人员在行业中需要8-10年的项目经验,并且精通业务。

JUNIT是一个比较常用的测试工具,准们可以进行Use Case测试的,在日后所开发的程序里都要写大量的JUNIT测试程序。

**范例:**定义要测试的程序

?
1
2
3
4
5
6
7
8
9
10
package com.util;
 
public class MyMath {
    private MyMath(){}
    public static int add(int x, int y){
        int temp = 0;
        temp = x + y;
        return temp;
    }
}

测试类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.test;
 
import static org.junit.Assert.*;
 
import org.junit.Test;
 
import com.util.MyMath;
 
import junit.framework.TestCase;
 
public class MyMathTest {
 
    @Test
    public void testAdd() {
        TestCase.assertEquals(MyMath.add(2, 3), 5);
    }
 
}

建立JUNIT测试的时候有两种形式:

​ 1.JUNIT Test Case:表示一个测试用例,主要完成一个业务的测试;

​ 2.JUNIT Test Case:表示一组测试用例,包含多个Test Case。

对于JUNIT的测试结果来说,一共分为两种:

​ 1.GREEM BAR:测试通过;

​ 2.RED BAR:测试失败。

2、Java基础新特性

Java的发展从1995年开始经历了许多的过程,但是有三个最具有代表性的JDK版本;

JDK1.0:标志着java的诞生;

JDK1.2:加入了javax.swing组件,这是主要新特性;

JDK1.5:标记为tiger,出现了许多一直沿用至今的特性;

JDK1.8:Lambda表达式、接口的定义加强

已经接触过了一些新特性,例如:自动装箱与拆箱、switch对String的判断支持。

2.1 可变参数

在讲解可变参数之前,首先思考一个问题:如果说现在要实现若干个整型变量的相加操作,问,此方法该如何设计?使用数组接收,因为参数个数不确定,按照之前所学,只能使用数组完成。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.demo;
 
/**
 * @author 张晟睿
 *
 */
public class TestDemo {
    public static void main(String[] args) {
        System.out.println(add(new int[]{1}));
        System.out.println(add(new int[]{1,2,3}));
        System.out.println(add(new int[]{1,2,3,4,5,6,7}));
    }
    
 /**
 * 实现任意个数的数据相加操作处理
 * @param data相加操作数据
 * @return  返回多个数据的相加结果
 */
public static int add(int [] data){
        int sum = 0;
        for (int i = 0; i < data.length; i++) {
            sum += data[i];
        }
        return sum;
    }
}

以上的确是实现了技术要求,但是现在有一个新的问题产生了:如果按照题目要求,应该是可以任意的传递多个数据,但是以上实际上传的是一个数据,只不过一个数据使用数组的形式封装。那么为了更好的解决这个问题,可以使用JDK1.5的可变参数的方式来解决此问题

?
1
2
3
Public [static]  [final] 返回值类型  方法名称(参数类型…变量){  //虽然方式改变了
    [return [返回值];]
}

发现现在进行方法参数的定义的时候有了一些变化,而这个时候的参数可以说是数组形式。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.demo;
 
/**
 * @author 张晟睿
 *
 */
public class TestDemo {
    public static void main(String[] args) {
        System.out.println(add(1));
        System.out.println(add(1,2,3));
        System.out.println(add(1,2,3,4,5,6,7));
    }
    
 /**
 * 实现任意个数的数据相加操作处理
 * @param data相加操作数据
 * @return  返回多个数据的相加结果
 */
public static int add(int ... data){
        int sum = 0;
        for (int i = 0; i < data.length; i++) {
            sum += data[i];
        }
        return sum;
    }
}

有了可变参数在日后进行方法调用的过程之中,就可以比较直观的传递任意多个参数,但是异常的操作在开发之中不建议使用,最好别用。

2.2 foreach输出

首先需要解释的是:foreach并不是新的概念,最早是在NET中提出来的,多为foreach可以理解为增强型的for循环,下面来回顾一下最早的for循环:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.demo;
 
/**
 * @author 张晟睿
 *
 */
public class TestDemo {
    public static void main(String[] args) {
        System.out.println(add(1));
        System.out.println(add(1,2,3));
        System.out.println(add(1,2,3,4,5,6,7));
        
        
    }
    
 /**
 * 实现任意个数的数据相加操作处理
 * @param data相加操作数据
 * @return  返回多个数据的相加结果
 */
public static int add(int ... data){//接收原始数组
        int sum = 0;
        for (int i : data) {    //将数组中的每一个元素设置给x
            sum += i;//这种循环避免了脚标的问题
        }
        return sum;
    }
}

但是有了foreach之后,那么对于数组或者是集合的输出就有了新的支持,语法如下:

?
1
2
3
for(数据类型  变量 :数组|集合){
    //操作代码
}

对于这种for循环避免了数组越界的问题,但依然只是要求会使用,能看懂就行,不过个人建议:最好别用。

2.3 静态导入

如果说想在想要导入一个不同包的类的方法,那么肯定使用import完成,即:如下是之前所采用的格式。

定义一个MyMath类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.util;
 
public class MyMath {
    private MyMath(){}
    public static int add(int x, int y){
        int temp = 0;
        temp = x + y;
        return temp;
    }
    public static int sub(int x,int y){
        return x-y;
    }
    public static int mul(int x,int y){
        return x*y;
    }
    public static int div(int x,int y){
        return x/y;
    }
}

在JDK1.5值周,如果一个雷之中的全部方法都是static型的,则可以使用如下的语法进行导入:

?
1
import static 包.类.*;

表示的是将这个指定类之中的全部方法导入进来,最后就好像这些方法全部都是在主类之中定义的一样。

?
1
2
3
4
5
6
7
8
9
10
package com.test;
 
import static com.util.MyMath.*;//静态导入
 
public class TestMath {
    public static void main(String[] args) {
        System.out.println(add(10,20));
        System.out.println(sub(30,10));
    }
}

这种比较难受的方法,也只是出现在讲课之中,本人是绝对不会使用的,你们也可以忘记它。

3、 JDK三大主要特性——泛型

泛型可以帮助我们解决参数转换的问题

3.1 泛型的引出

下面首先通过一个简单分析来研究一下泛型出现的主要目的是什么?例如现在要求定义一个表示坐标的操作类(Point)这个类可以表示三种类型的坐标:

​ 整数坐标:x=10、y=20;

​ 小数坐标:x=10.1、y=20.3;

​ 字符串数据:x=“东经10度”、y=“西经20度”。

类之中如果想要表示以上的数据,一定需要定义x和y两个属性,而且每一个属性可以接收三种数据类型,那么只能使用Object类来定义会比较合适,这样会发生如下的几种转换关系:

整数:int→自动装箱为Integer→向上转型为Object;

小数:double→自动装箱为Double→向上转型为Obejct;

字符串:字符串→向上转型为Obejct;

设置整形

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.demo;
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;
    }
}
public class PointDemo {
    public static void main(String[] args) {
        //第一步:设置数据
        Point p = new Point();
        p.setX(10);
        p.setY(20);
        //第二步:取出数据
        int x = (Integer)p.getX();
        int y = (Integer)p.getY();
        System.out.println("x = " + x + ",y = " + y);
    }
}

设置小数

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.demo;
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;
    }
}
public class PointDemo {
    public static void main(String[] args) {
        //第一步:设置数据
        Point p = new Point();
        p.setX(10.1);
        p.setY(20.2);
        //第二步:取出数据
        double x = (Double)p.getX();
        double y = (Double)p.getY();
        System.out.println("x = " + x + ",y = " + y);
    }
}

设置字符串

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.demo;
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;
    }
}
public class PointDemo {
    public static void main(String[] args) {
        //第一步:设置数据
        Point p = new Point();
        p.setX("东经10");
        p.setY("西经20");
        //第二步:取出数据
        String x = (String)p.getX();
        String y = (String)p.getY();
        System.out.println("x = " + x + ",y = " + y);
    }
}

看起来所有功能都实现了,并根据之前所学的内容,也只能做到这些了,但是本程序还有一系列问题。

本程序解决问题的关键就在Object类,所有的类型都可以想Obejct转换,但是成也是它败也是它。

?
1
2
3
4
5
6
7
8
9
10
11
12
public class PointDemo {
    public static void main(String[] args) {
        Point point = new Point();
        //设置参数
        point.setX(10);
        point.setY("北纬");
        //取出参数
        String x = (String) point.getX();
        String y = (String) point.getY();
        System.out.println("x的坐标是:"+x+"y的坐标是:"+y);
    }
}

这个时候程序并没有任何的语法错误,因为数字10 被包装成了Integer,可以使用Obejct接收,从技术上而言,本操作没有问题,但是从实际来讲,因为没有统一,多以在取得数据并且执行向下转型的过程中就会出现如下的错误提示信息:

?
1
2
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
    at cn.mldn.demo.TestDemo.main(PointDemo.java:30)

所以,就可以得出一个结论,以上的程序存在安全隐患,但是并没有在程序的编译过程中检查出来,而现在就可以利用泛型来解决这种问题。

3.2 泛型实现

泛型:类之中操作的属性或方法的参数类型不在定义的时候声明,而是在使用的时候动态设置。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.demo;
//在定义Point不知道是什么类型,由使用者来进行定义使用
class Point<T> {//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;
    }
}
public class PointDemo {
    public static void main(String[] args) {
        //第一步:设置数据
        Point<String> p = new Point<String>();
        p.setX("东经10");
        p.setY("西经20");
        //第二步:取出数据
        String x = p.getX();//避免了向下转型
        String y = p.getY();
        System.out.println("x = " + x + ",y = " + y);
    }
}

测试没有了向下转型的操作关系,那么程序就避免了安全性的问题,而且如果设置的类型不统一,在程序编译的过程之中也是可以很好的解决了,直接会报出语法错误。

而且当用户在使用Point类声明对象的时候没有设置泛型,程序在编译的过程之中,会提示警告信息,而且为了保证程序不出现错误,所有的类型都将使用Obejct进行处理。使用泛型可以很好的解决数据类型的统一问题。

但是在此处需要提醒的是,JDK1.5和JDK1.7在定义泛型的时候是稍微有些区别的。

JDK1.5的时候声明泛型的操作

?
1
Point<String> p= new Point<String>();

以上是JDK1.5的语法,在声明对象和实例化对象的时候都必须设置好泛型类型。

JDK1.7的时候简化了

?
1
Point<String> p= new Point< >();

​ 这个时候实例化对象时泛型的泛型类型就通过声明时泛型类型来定义了。

3.3 通配符

泛型的而出现的确是可以解决了数据的统一问题以及避免了向下转型操作,但同事也会带来新的问题,下面通过一段程序,来观察一下会产生什么问题?

为了简化定义一个简单的泛型

?
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.demo;
 
class Message<T>{
    private T info;
 
    public T getInfo() {
        return info;
    }
 
    public void setInfo(T info) {
        this.info = info;
    }
}

以上的类对象进行引用传递

?
1
2
3
4
5
6
7
8
9
10
public class MessageDemo {
    public static void main(String[] args) {
        Message<String> msg = new Message<>();
        msg.setInfo("hello,world!");
        print(msg);//以上的类对象进行引用传递
    }
    public static void print(Message<String> s){
            System.out.println(s.getInfo());
    }
}

但是如果现在定义的泛型类型不是String呢?例如:换成了int(不能是基本数据类型,只能是包装类)

?
1
2
3
4
5
6
7
8
9
10
public class MessageDemo {
    public static void main(String[] args) {
        Message<Integer> msg = new Message<>();
        msg.setInfo(100);
        print(msg);//无法进行引用传递
    }
    public static void print(Message<String> s){
            System.out.println(s.getInfo());
    }
}

发现这个时候的print()方法无法再接收Message对象的引用,因为这个方法只能够接收Message对象的引用,那么可以将print()方法重载换成Message

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class MessageDemo {
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        Message<Integer> msg = new Message<>();
        msg.setInfo(100);
        print(msg);
    }
    public static void print(Message<String> msg){
        System.out.println(msg.getInfo());
    }
    public static void print(Message<Integer> msg){
        System.out.println(msg.getInfo());
    }
}

这个时候发现按照之前的方式根本就无法进行方法的重载,方法的重载没有说为一个类而定义的,因为方法重载的时候观察的不是泛型类型,而是类的名称,或者说是数据类型的,所以现在就可以发现,这个给出了泛型类之后,就相当于将一个类又划分成了几个小类。

Java泛型枚举Annotation接口详细解读与Eclipse发展

那么现在的问题:方法接收的参数问题又严重了,而且比之前使用对象多态性解决问题时出现的麻烦更大了,至少那个时候可以利用重载来接收一个类的所有子类对象,而现在连重载都使用不了。

​ 这个时候,有人提出了,干脆在定义方法的时候就别写泛型类型了。

定义方法的时候不定义泛型类型

?
1
2
3
4
5
6
7
8
9
10
11
public class MessageDemo {
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        Message<Integer> msg = new Message<>();
        msg.setInfo(100);
        print(msg);
    }
    public static void print(Message msg){
        System.out.println(msg.getInfo());
    }
}

虽然现在print()方法的参数上出现了警告,但是现在的程序可算是正常了,但是新的问题又来了。问题就在于方法操作中,没有类型限制了。

?
1
2
3
4
public static void print(Message msg){
        msg.setInfo(100);
        System.out.println(msg.getInfo());
}

发现此时在print()方法之中操作的时候,由于没有设置泛型类型,那么所有类型都统一变为了Object,也就可以修改了。而通过本程序也就发现了,必须找到一种方法,:此方法可以接收任意的泛型类型的设置,并且不能修改,只能输出,为了解决这样的问题,可以使用通配符“?”表示。

?
1
2
3
public static void print(Message<?> msg){
        System.out.println(msg.getInfo());
}

由于“?”出现的情况较多,尤其在学习一些类库的时候,所以对于“?”就记住一点,表示任意类型,如果有参数返回的时候也是这个“?”,当成Object进行理解。

既然现在谈到了Obejct,那么现在实际上又有了另外一个问题:对于所有的子类,都是Object子类,那么如果对于之前的程序都使用Object能不能接收?

?
1
2
Message<String> msg = new Message<>();
Message<Object> s = msg;

因为Object的范围比String的范围大。

而在通配符“?”上有衍生出了两个子符号:

设置泛型的上限:?extends 类;

​ 例如:?extends Number,表示只能是Number或者是Number的子类Integer等;

​ 2.设置泛型的下限:?super类;

​ 例如:?super String,表示只能是String或者是String的父类(Object)

设置泛型上限

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.demo;
 
class Message<T extends Number>{
    private T info;
 
    public T getInfo() {
        return info;
    }
 
    public void setInfo(T info) {
        this.info = info;
    }
}
public class MessageDemo {
    public static void main(String[] args) {
        Message<Integer> msg = new Message<>();
        msg.setInfo(100);
        //100
        print(msg);
    }
    public static void print(Message<? extends Number> s){
            System.out.println(s.getInfo());
    }
}

设置泛型下限

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.demo;
 
class Message<T>{
    private T info;
 
    public T getInfo() {
        return info;
    }
 
    public void setInfo(T info) {
        this.info = info;
    }
}
public class MessageDemo {
    public static void main(String[] args) {
        Message<String> msg = new Message<>();
        msg.setInfo("Hello,world!100");
        //Hello,world!100
        print(msg);
    }
    //此时使用通配符“?”描述的是它可以接收任何任意数据类型,但是由于不确定类型,无法修改
    public static void print(Message<? super String> s){
            System.out.println(s.getInfo());
    }
}

3.4 泛型接口

在之前的所有定义的泛型之中,都是在类上定义的,而对于接口也是可以进行泛型定义的,而使用泛型定义的接口可以称为泛型接口。

?
1
2
3
interface Message<T>{
    public String echo(T msg);
}

而对于泛型接口的实现,在Java中有两种方式:

方式一:在子类上继续定义泛型,同时此泛型继续在接口上使用

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package com.test;
interface IMessage<T>{
    public void print(T t);
}
class MessageImpl<T> implements IMessage<T>{
 
    @Override
    public void print(T t) {
        // TODO Auto-generated method stub
        System.out.println(t);
    }
 
    
}
public class MessageTest {
    public static void main(String[] args) {
        IMessage<String> msgimpl = new MessageImpl();
        msgimpl.print("Hello,world!!");
    }
}

方式二:在子类上设置具体类型

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.test;
interface IMessage<T>{
    public void print(T t);
}
class MessageImpl implements IMessage<String>{
 
    @Override
    public void print(String t) {
        // TODO Auto-generated method stub
        System.out.println(t);
    }
    
}
public class MessageTest {
    public static void main(String[] args) {
        IMessage<String> msgimpl = new MessageImpl();
        msgimpl.print("Hello,world!!");
    }
}

3.5 泛型方法

对于泛型除了可以在类上定义,也可以在方法上定义,而在方法上进行泛型的时候这个方法不一定非在泛型类中定义。

?
1
2
3
4
5
6
7
8
9
10
11
12
public class TestDemo {
    public static void main(String[] args) {
        // TODO 自动生成的方法存根
        Integer result[] = get(1,2,3);
        for(int temp : result){
            System.out.println(temp);
        }
    }
    public static <T> T[] get(T... date){
        return date;
    }
}

4、JDK三大主要特性——枚举

在讲解枚举之前回顾一个概念:多例设计模式,构造方法私有化(非public),之后在类的内部存在若干个指定的对象,通过一个方法返回指定对象。

4.1 多例与枚举

定义一个描述颜色基色的多例设计类

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
package com.demo;
class Color {
    private static final Color RED = new Color("红色");
    private static final Color GREEN = new Color("绿色");
    private static final Color BLUE = new Color("蓝色");
    private String title;
    private Color(String title){
        this.title=title;
    }
    public String toString(){
        return this.title;
    }
    public static Color getColor(int num){
        switch(num){
        case 0:
        return RED;
        case 1:
        return GREEN;
        case 2:
        return BLUE;
        default:
        return null;
        }
    }
}
public class ColorDemo {
    public static void main(String[] args) {
        Color c = Color.getColor(0);
        System.out.println(c);
    }
}

基于枚举开发

?
1
2
3
4
5
6
7
8
9
package com.demo;
enum Color {
    RED,BULE,PINK;
}
public class ColorDemo {
    public static void main(String[] args) {
        System.out.println(Color.RED);
    }
}

4.2 Enum类

很明显,现在可以发现,利用枚举实现多例设计会更加的简单直白一些,但是在Java之中,枚举并不是一个新的类型,严格来讲,每一个使用enum定义的类实际上都属于一个类继承了Enum父类而已,而java.lang.Enum类定义如下:

?
1
2
3
public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable

而在Enum类种子红定义了两个方法:

取得枚举的序号:public final int ordinal();

取得枚举的名称:public final String name()。

?
1
2
3
4
5
6
7
8
9
10
package com.demo;
enum Color {
    RED,BULE,PINK;
}
public class ColorDemo {
    public static void main(String[] args) {
        //0===RED
        System.out.println(Color.RED.ordinal() + "===" + Color.RED.name());
    }
}

取得所有颜色数据

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.demo;
enum Color {
    RED,BULE,PINK;
}
public class ColorDemo {
    public static void main(String[] args) {
                /*0===RED
                1===BULE
                2===PINK*/
        for (Color c : Color.values()) {
            System.out.println(c.ordinal() + "===" + c.name());
        }
        
    }
}

面试题:请解释enum和Enum的区别?

enum是一个关键字,使用enum定义的枚举类本质上相当于一个类继承了Enum类而已。

4.3 枚举中定义其它结构

按照之前所理解,枚举就属于多例设计模式,那么既然是多例设计模式,对于类之中就肯定有多种组成,包括属性,方法,构造方法,在枚举之中也同样可以定义以上的内容,不过需要注意的是,枚举类之中定义的构造方法绝对不能是public,必须私有化。

除了这些要求之外枚举之中每一个定义的对象必须定义在第一行。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.demo;
enum Color {
    RED("红色"),BULE("蓝色"),PINK("粉色");
    private String c;
    private Color(String c){
        this.c = c;
    }
    public String toString(){
        return this.c;
    }
}
public class ColorDemo {
    public static void main(String[] args) {
                /*红色*/
        System.out.println(Color.RED);
    }
}

枚举接口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.demo;
interface IColor{
    public String getColor();
}
enum Color implements IColor{
    RED("红色"),BULE("蓝色"),PINK("粉色");
    private String c;
    private Color(String c){
        this.c = c;
    }
    public String toString(){
        return this.c;
    }
    @Override
    public String getColor() {
        // TODO Auto-generated method stub
        return this.c;
    }
}
public class ColorDemo {
    public static void main(String[] args) {
                /*红色*/
        System.out.println(Color.RED);
    }
}

4.4 枚举应用

只有指定的几个对象

性别

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.demo;
class Person{
    private String name;
    private int age;
    private Sex sex;
    public Person(String name, int age, Sex sex) {
        super();
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", sex=" + sex + "]";
    }
}
enum Sex{
    MALE("男"),FEMALE("女");
    private String sex;
 
    private Sex(String sex) {
        this.sex = sex;
    }
    public String toString(){
        return this.sex;
    }
}
public class MaleDemo {
    public static void main(String[] args) {
        Person person = new Person("jack", 10, Sex.MALE);
        System.out.println(person.toString());
    }
}

枚举还可以进行switch语句进行编写和判断。

5、JDK三大主要特性——Annotation

在JDK1.5之后,程序允许通过注解(Annotation)的方式来进行程序的定义,而在JavaSE之中攒在了三种Annotation:@Override、@Deprecated、@SuppressWarnings。

5.1 准确的覆写:@Override

方法的覆写:发生继承关系之中,子类定义了与父类的方法名称相同、参数类型以及个数相同的覆写,被覆写的方法不能够拥有比父类更为严格的访问控制权限。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.annotation;
class Person{
    //现在是希望进行toString()覆写,但遗憾的由于你自己的输入错误,导致方法的覆写错误
    //@Override
    public String tostring(){//现在希望可以进行toString()方法的覆写
        return "一个人";
    }
}
public class Demo1 {
    public static void main(String[] args) {
        System.out.println(new Person().tostring());
    }
}

这个时候不叫覆写,属于自己定义一个扩展的方法,最为重要的是,这个问题在程序编译的根本就无法显示出来。但是现在为了保证我们的覆写方法的严格,可以使用一个注解(@Override)来检测:如果该方法确定成的覆写了

,则不会有我们的语法错误,如果进行成功的覆写,认为语法的错误。

?
1
2
3
4
5
6
7
8
9
10
11
12
package com.annotation;
class Person{
    //现在是希望进行toString()覆写,但遗憾的由于你自己的输入错误,导致方法的覆写错误
    public String toString(){//现在希望可以进行toString()方法的覆写
        return "一个人";
    }
}
public class Demo1 {
    public static void main(String[] args) {
        System.out.println(new Person());
    }
}

5.2 声明过期操作:@Deprecated

对于程序开发而言,往往一些使用的类要进行修改或者是维护,如果说现在一个类之中的某个方法,可能一开始推出的时候正常使用,但是在后面的版本就存在了一些问题,在修改之后不希望人再去使用这些方法,那么肯定不能直接删除,因为如果直接删除了,那么之前的程序就会出现问题了,所以最好的做法是告诉用户:这个方法存在了问题,不建议再使用了,这个时候就使用“@Deprecated”声明。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.annotation;
class Person1{
    @Deprecated//表示该方法不建议使用,即使使用仍然不会报错
    public Person1(){}
    public Person1(String name){}
    @Deprecated
    public void print(){}
}
public class Demo2 {
    public static void main(String[] args) {
        Person1 person = new Person1();//明确标记过期
        person.print();
    }
}

5.3 压制警告:@SuppressWarning

程序在编译的时候如果提示警告但是不会报错只是存在了某些安全隐患,肯定会提示用户,所以不想让其显示的话,就增加压制警告信息。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.annotation;
class Person1<T>{
    @Deprecated//表示该方法不建议使用,即使使用仍然不会报错
    public Person1(){}
    public Person1(String name){}
    @Deprecated
    public void print(){}
}
public class Demo2 {
    @SuppressWarnings("rawtypes")
    public static void main(String[] args) {
        Person1 person = new Person1();//明确标记过期
        person.print();
    }
}

Java泛型枚举Annotation接口详细解读与Eclipse发展

关于软件的开发模式;

​ 第一阶段:会将所有的操作都写在程序之中,例如:网络程序,连接程序,连接的服务器地址,用户验证等;

​ 第二阶段:程序+配置文件,配置文件和程序相分离,配置文件过多,后期修改非常复杂;

​ 第三阶段:将配置文件写回到程序之中,但是和程序进行有效的分离。

6、接口定义加强

Java泛型枚举Annotation接口详细解读与Eclipse发展

造成此种尴尬的局面的核心问题在于,接口只是一个方法的声明,而没有具体方法的实现,所以随着时间的推移,如果出现以上的问题,该接口将无法继续使用。从JDK1.8为了解决这个问题,专门提供两种专门的接口。

可以使用default来定义普通方法,需要通过对象调用。可以使用static来定义静态方法,通过接口名就能使用。

定义普通方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.annotation;
interface IMess{
    public default void fun(){//追加普通方法,又方法体了
        System.out.println("hello,world!");
    }
    public void print();
}
class MessImpl implements IMess{
 
    @Override
    public void print() {
        // TODO Auto-generated method stub
        System.out.println("www.baidu.com");
    }
    
}
public class Demo3 {
    public static void main(String[] args) {
        MessImpl msg = new MessImpl();
        msg.print();
        msg.fun();
    }
}

定义static方法

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.annotation;
interface IMess{
    public default void fun(){//追加普通方法,又方法体了
        System.out.println("hello,world!");
    }
    public static IMess getInstance(){//定义静态方法
        return new MessImpl();
    }
    public void print();
}
class MessImpl implements IMess{
 
    @Override
    public void print() {
        // TODO Auto-generated method stub
        System.out.println("www.baidu.com");
    }
    
}
public class Demo3 {
    public static void main(String[] args) {
//      MessImpl msg = new MessImpl();
        IMess msg = IMess.getInstance();
        msg.print();
        msg.fun();
    }
}

整体来说,接口更像抽象类,但是比抽象类强大在于,接口的子类依然可以实现多继承的关系,而抽象类继续保持单继承。

7、Lambda表达式

最具有代表性的就是haskell.函数式编程和面向对象编程为两大开发阵营

传统的面向对象开发

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.annotation;
interface IMess{
    public void print();
}
public class Demo3 {
    public static void main(String[] args) {
        IMess msg = new IMess(){
            public void print(){
                System.out.println("Hello,world!");
            };
        };
        msg.print();
    }
}

使用匿名内部类来实现接口最大好处就是节约了一个文件,最大的缺点就是看的眼花缭乱,对于此操作有了更简化的体现。如果采用函数式编程模型。

函数式编程模型

?
1
2
3
4
5
6
7
8
9
10
package com.annotation;
interface IMess{
    public void print();
}
public class Demo3 {
    public static void main(String[] args) {
        IMess msg = ()->System.out.println("Hello,world!");
        msg.print();
    }
}

如果想要使用函数式编程前提,接口只能写一个方法,如果编写两个方法,则会出现语法错误。可以在接口的开头加上@FunctionalInterface声明这是一个函数接口。

实际上对于以上的语法形式:

(参数 )->单行语句;

Java泛型枚举Annotation接口详细解读与Eclipse发展

这个时候方法本身只包含一行语句,那么直接编写语句即可,如果要是有多行语句,则就需要我们使用"{}"

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.annotation;
@FunctionalInterface
interface IMess{
    public void print();
}
public class Demo3 {
    public static void main(String[] args) {
        IMess msg = ()->{
            System.out.println("Hello,world!");
            System.out.println("Hello,world!");
            System.out.println("Hello,world!");
        };
        msg.print();
    }
}

如果现在你的表达式里面的内容只是一行进行数据的返回,那么直接使用语句即可,不用写return。

?
1
2
3
4
5
6
7
8
9
10
package com.annotation;
interface IMath{
    public int add(int x, int y);
}
public class Demo4 {
    public static void main(String[] args) {
        IMath msg = (p1, p2)-> p1 + p2;
        System.out.println(msg.add(10, 20));
    }
}

到此这篇关于Day11基础不牢地动山摇-Java基础的文章就介绍到这了,更多相关Java基础内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/zsr6135/article/details/119721881

延伸 · 阅读

精彩推荐