Java学习笔记(六):Java泛型

文章目录

  • Java学习笔记(六):Java泛型
    • 前言
      • (一)泛型(Generic)的概念
      • (二)为什么要引入泛型呢?
      • (三)在集合中使用泛型(关于集合看下篇博文,点击跳转)
      • (四) 自定义泛型结构
        • 1 - 泛型类(order.java)
        • 2 - 泛型接口
        • 3 - 泛型方法(order.java)
      • (五)泛型的类型擦除机制
        • 1 - 各种语言中的编译器是如何处理泛型的(了解泛型的各种处理方式)
        • 2 - 什么是类型擦除
        • 3 - 类型擦除测试Demo
          • ① 搭建环境(IDEA+反编译工具fernflower)
          • ② 开始敲代码啦!(为了让大伙手敲,我选择截图诶嘿嘿)
      • (六)泛型与继承
        • 1 - 子类继承泛型父类,但此时子类不是泛型类
        • 2 - 子类继承泛型父类,子类此时也是一个泛型类
        • 3 - 子类继承指定泛型的父类,同时子类此时也是一个泛型类
        • 4 - 子类继承泛型父类,同时此时子类也是一个泛型类,但是子类的泛型种类多于父类
      • (七)泛型通配符
        • 1 - 常用通配符分类:
        • 2 - 无边界通配符:<?>
        • 3 - 固定上边界的通配符:<? extends E>
        • 4 - 固定下边界的通配符:<? super E>
        • 5 - 如何理解边界
        • 6 - 通配符使用原则
      • (八)什么情况下不能使用泛型?
        • 1 - 基本类型无法直接使用泛型
        • 2 - 泛型类型不能被实例化
        • 4 - 泛型无法持有静态类型
        • 5 - 泛型无法进行instanceof判断
        • 6 - 泛型数组不合法
      • (九)参考资料
    • 最后的最后

前言

​ 一般的类和方法,只能使用具体的类型:要么是基本类型,要么是自定义的类。如果要编写可以应用于多种类型的代码,这种刻板的限制对代码束缚很大。 ----------Java编程思想

(一)泛型(Generic)的概念

​ 所谓泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实际的类型参数,也称为类型实参)。

但泛型还有一种较为准确的说法就是为了参数化类型,或者说可以将类型当作参数传递给一个类或者是方法。

​ JDK1.5改写了集合框架中的全部接口和类,为这些接口、类增加了泛型支持,从而可以在声明集合变量、创建集合对象时传入类型实参。(一般泛型的应用也都以集合为主,泛型与集合强相关,所以应该有所重视)

  • 泛型的栗子(看不懂先跳过这部分,建议看完为什么引入泛型部分再看,会有更好的理解):
//栗子一:集合(容器)的泛型(关于Java集合/容器请看我的下篇博文)
//1、指定此List中只能保存字符串类型的对象
List<String>
//2、指定此Set中只能保存整型类型的对象
Set<Integer>
//3、指定此Map中只能保存Integer、String的键值
Map<Integer,String>//栗子二:泛型类
//其中的T在创造对象的时候确定
//File:Cache.java
public class Cache<T> {T value;public Object getValue() {return value;}public void setValue(T value) {this.value = value;}
}//File:GenericTest.java
public class GenericTest{public static void main(String[] args) {Cache<String> cache1 = new Cache<String>();cache1.setValue("123");String value2 = cache1.getValue();Cache<Integer> cache2 = new Cache<Integer>();cache2.setValue(456);int value3 = cache2.getValue();}
}

泛型的理解:标签

  • 中药店,每个抽屉外面贴着标签
  • 超市购物架上很多种类型的货品,每个货品都是什么类型,有标签
  • Java7以前的版本使用泛型类型,需要在声明并赋值的时候,两侧都加上泛型类型,就像上面栗子二创建对象那样。

  • Java8中引入了类型推导,类型推导也就是指编译器能够根据你调用的方法和相应的声明来确定需要的参数类型的能力。

Holder<String> holder = new Holder<>("CalvinHaynes"); //Java8
  • 官方文档中还给出了一个例子:
static <T> T pick(T a1, T a2) { return a2; }
Serializable s = pick("d", new ArrayList<String>());

在这里,编译器能够推导出传入pick方法中的第二个参数的类型是Serializable的。

  • 之前版本,需要这样写,指明泛型方法的泛型类型:
Serializable s = this.<Serializable>pick("d", new ArrayList<String>());

(二)为什么要引入泛型呢?

  • 解决元素存储的安全性问题,好比商品、药品标签,不会弄错。
  • 解决获取数据元素时,需要类型强制转换的问题,好比不用每回拿商品、药
    品都要辨别。
  1. 与普通的 Object 代替一切类型这样简单粗暴而言,泛型使得数据的类别可以像参数一样由外部传递进来。它提供了一种扩展能力。它更符合面向抽象开发的软件编程宗旨。
  2. 当具体的类型确定后,泛型又提供了一种类型检测的机制,只有相匹配的数据才能正常的赋值,否则编译器就不通过。所以说,它是一种类型安全检测机制,一定程度上提高了软件的安全性防止出现低级的失误。
  3. 泛型提高了程序代码的可读性,不必要等到运行的时候才去强制转换,在定义或者实例化阶段,因为 Cache<String>这个类型显化的效果,程序员能够一目了然猜测出代码要操作的数据类型。

(三)在集合中使用泛型(关于集合看下篇博文,点击跳转)

  • Demo1:List接口的ArrayList实现类
ArrayList<Integer> list = new ArrayList<>();//类型推断list.add(78);
list.add(88);
list.add(77);
list.add(66);//遍历方式一:增强for循环
for(Integer i : list){//不需要强转System.out.println(i);
}//遍历方式二:迭代器
Iterator<Integer> iterator = list.iterator();while(iterator.hasNext()){System.out.println(iterator.next());
}
  • Demo2:Map
Map<String,Integer> map = new HashMap<String,Integer>();map.put("Tom1",34);
map.put("Tom2",44);
map.put("Tom3",33);
map.put("Tom4",32);//添加失败
//map.put(33, "Tom");//泛型的嵌套,可以参考Map.java中Entry接口的定义interface Entry<K,V>
Set<Entry<String,Integer>> entrySet = map.entrySet();Iterator<Entry<String,Integer>> iterator =  entrySet.iterator();while(iterator.hasNext()){   Entry<String,Integer> entry = iterator.next();System.out.println(entry.getKey() + "--->" + entry.getValue());
}

(四) 自定义泛型结构

1 - 泛型类(order.java)

/**Order.java* Created with IntelliJ IDEA.* Description:自定义泛型类* User: CalvinHaynes* Date: 2021-05-26* Time: 21:19*/
public class Order<T> {String orderName;int orderId;//类的内部结构就可以使用类的泛型T orderT;public Order() {}public Order(String orderName, int orderId, T orderT) {this.orderName = orderName;this.orderId = orderId;this.orderT = orderT;}//如下的三个方法都不是泛型方法public T getOrderT(){return orderT;}public void setOrderT(T orderT){this.orderT = orderT;}@Overridepublic String toString() {return "Order{" +"orderName='" + orderName + '\'' +", orderId=" + orderId +", orderT=" + orderT +'}';}
}

2 - 泛型接口

// A generic interface.
public interface GenericInterface<T> {public T write(T t);
}
  • 实现泛型接口的实现类:
public class Generic3 implements GenericInterface<String>{    @Override    public String write(String s) {        return s;    }}
  • 泛型接口测试类:
public class GenericTest3 {    public static void main(String[] args) {        Generic3 generic3 = new Generic3();        String hello = generic3.write("hello");        System.out.println(hello);    }}/*OutPut:hello*/

3 - 泛型方法(order.java)

泛型类,是在实例化类的时候指明泛型的具体类型;泛型方法,是在调用方法的时候指明泛型的具体类型 。

/**Order.java* 泛型方法的Demo** 说明:*   1.public 与返回值T中间的<T>非常重要,可以理解为对于泛型方法的声明*   2.只有声明了<T>的方法才是泛型方法,泛型类中使用泛型的成员方法并不是泛型方法*  3.<T>表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。*  4.与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型**/public <E> List<E> copyFromArrayToList(E[] arr){    ArrayList<E> list = new ArrayList<>();    for(E e : arr){        list.add(e);    }    return list;}
//泛型方法测试@Testpublic void test4(){    Order<String> order = new Order<>();    Integer[] arr = {1, 2, 3, 4};        //泛型方法在调用时,指明泛型参数的类型。    List<Integer> integers = order.copyFromArrayToList(arr);    System.out.println(integers);}

(五)泛型的类型擦除机制

1 - 各种语言中的编译器是如何处理泛型的(了解泛型的各种处理方式)

通常情况下,一个编译器处理泛型有两种方式:

1.Code specialization。在实例化一个泛型类或泛型方法时都产生一份新的目标代码(字节码or二进制代码)。例如,针对一个泛型list,可能需要 针对stringintegerfloat产生三份目标代码。

2.Code sharing。对每个泛型类只生成唯一的一份目标代码;该泛型类的所有实例都映射到这份目标代码上,在需要的时候执行类型检查和类型转换。

**C++**中的模板(template)是典型的Code specialization实现。C++编译器会为每一个泛型类实例生成一份执行代码。执行代码中integer liststring list是两种不同的类型。这样会导致代码膨胀(code bloat)。 C#里面泛型无论在程序源码中、编译后的IL中(Intermediate Language,中间语言,这时候泛型是一个占位符)或是运行期的CLR中都是切实存在的,List<int>List<String>就是两个不同的类型,它们在系统运行期生成,有自己的虚方法表和类型数据,这种实现称为类型膨胀,基于这种方法实现的泛型被称为真实泛型Java语言中的泛型则不一样,它只在程序源码中存在,在编译后的字节码文件中,就已经被替换为原来的原生类型(Raw Type,也称为裸类型)了,并且在相应的地方插入了强制转型代码,因此对于运行期的Java语言来说,ArrayList<int>ArrayList<String>就是同一个类。所以说泛型技术实际上是Java语言的一颗语法糖,Java语言中的泛型实现方法称为类型擦除,基于这种方法实现的泛型被称为伪泛型

C++C#是使用Code specialization的处理机制,前面提到,他有一个缺点,那就是会导致代码膨胀。另外一个弊端是在引用类型系统中,浪费空间,因为引用类型集合中元素本质上都是一个指针。没必要为每个类型都产生一份执行代码。而这也是Java编译器中采用Code sharing方式处理泛型的主要原因。

Java编译器通过Code sharing方式为每个泛型类型创建唯一的字节码表示,并且将该泛型类型的实例都映射到这个唯一的字节码表示上。将多种泛型类形实例映射到唯一的字节码表示是通过类型擦除type erasue)实现的。

2 - 什么是类型擦除

泛型信息只存在于代码编译阶段,在进入 JVM 之前,与泛型相关的信息会被擦除掉,专业术语叫做类型擦除

类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。 类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。

3 - 类型擦除测试Demo

通过几个Demo逐步理解类型擦除的过程

这部分大家最好自己动手敲一遍 ,我会以做实验的方式讲解这部分,一点点渗透。

① 搭建环境(IDEA+反编译工具fernflower)
  • 查看反编译代码(反编译是class字节码到源代码)–利用反编译工具fernflower,关于这个fernflower工具怎么在IDEA用请自行查找,因为实在有些复杂,建议大家和我一样选择在线反编译:
  • 网址:http://www.javadecompilers.com/
  • 使用方式:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oeHwsXew-1622555098989)(https://cdn.jsdelivr.net/gh/CalvinHaynes/ImageHub@main/BlogImage/屏幕截图 2021-05-30 231540.104q47jazo34.png)]

② 开始敲代码啦!(为了让大伙手敲,我选择截图诶嘿嘿)
  • Demo1(泛型类)

可以发现泛型都不见了,程序又变回了Java泛型出现之前的写法,泛型类型都变回了原生类型。

  • Demo2(泛型接口)

  • Demo3(含有继承关系的泛型)

含继承关系的泛型擦除机制是:先将所有类型转换为最上边界,然后去掉泛型参数。(上下边界的理解在下文泛型通配符的理解边界一节)

例如上面的Demo3:<A extends Comparable> A --> Comparable --> Comparable

(六)泛型与继承

对于泛型的继承,无论子类是否是泛型类,有多少种泛型,所继承/实现的父类/接口,必须被指定,否则编译报错。

指定的两种情况:

  1. 在创建子类的时候就指定父类的泛型:class Son extends Father
  2. 需要在实例化子类的时候指定父类的泛型:class Son extends Father

1 - 子类继承泛型父类,但此时子类不是泛型类

//存在父类class Father<T> {    T name;}class Son extends Father<String> {}//此时, 子类继承过后的代码应该是class Son {    String name;}

2 - 子类继承泛型父类,子类此时也是一个泛型类

class Son<T> extends Father<T> {    public T print(T a) {        System.out.println(a);        return a;    }}//此时, 子类继承过后的代码应该是class Son {    T name;    public T print(T a) {        System.out.println(a);        return a;    }}

3 - 子类继承指定泛型的父类,同时子类此时也是一个泛型类

class Son<T> extends Father<String> {    public T print(T a) {        System.out.println(a);        return a;    }}//此时, 子类继承过后的代码应该是这样的, 注意, 继承父类的泛型, 被指定了. 但是, 子类拥有自己的泛型T, 并没有被指定, 所以继承过后如下class Son<T> extends Father<String> {    String name;        public T print(T a) {        System.out.println(a);        return a;    }}

4 - 子类继承泛型父类,同时此时子类也是一个泛型类,但是子类的泛型种类多于父类

class Son<T, E> extends Father<T> {    public E print(E e) {        System.out.println(e);        return e;    }}// 这个时候, 子类的T和父类的T是一个泛型, 继承过后是这样的class Son <T, E> {    T name;        public E print(E e) {        System.out.println(a);        return a;    }}

(七)泛型通配符

Java泛型中的通配符机制的目的是

  • 分类出一些便于理解的占位符号作为泛型,在实例化的时候根据用户设置的类型覆盖占位(T、K、V、E、N等)

  • 让一个持有特定类型(比如A类型)的集合能够强制转换为持有A的子类或父类型的集合(带?的通配符)

1 - 常用通配符分类:

  • T:type,表示具体的一个Java类型(Java类)
  • K,V:Key,Value分别代表Java键值中的Key,Value
  • E:element,代表一个元素 (在集合中使用,因为集合中存放的是元素)
  • N:Number,代表一个数值(数值类型)
  • ?:表示不确定的java类型

2 - 无边界通配符:<?>

  • 无边界的通配符的主要作用就是让泛型能够接受未知类型的数据,比如List<?>,它的意思是这个集合是一个可以持有任意类型的集合,它可以是List,也可以是List,或者List等等。

  • List<?>是List、List等各种泛型List的父类。

  • 因为不知道集合是哪种类型,所以只能够对集合进行读操作,并且读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型是什么,集合中包含的所有对象一定都是Object。

  • 实例Demo:

public static void main(String[] args) {    List<?> list = null;    list = new ArrayList<String>();    list = new ArrayList<Double>();    // list.add(3);//编译不通过,不能对使用无边界通配符的集合进行写操作    list.add(null);//由于null是所有类型的一个成员,所以是可以写入null的    list.get(0);//读取List<?>的对象list中的元素时,永远是安全的,因为不管list的真实类型                //是什么,集合中包含的所有对象一定都是Object。}

3 - 固定上边界的通配符:<? extends E>

  • 使用固定上边界的通配符的泛型,就能够接受指定类E及其子类类型的数据,或者说接收指定接口E的所有实现类。
  • List<? extends A> 代表的是一个可以持有 A及其子类(如B和C)的实例的List集合。
  • 当集合所持有的实例是A或者A的子类的时候,此时从集合里读出元素并把它强制转换为A是安全的(安全的向上转型)。下面是一个Demo实例:(不理解向上转型和向下转型的戳这里–> (๑´ㅂ`๑) )

此时向集合中添加元素的操作是不允许的,除非添加null,因为null是任何数据类型都有的值,继承A或者实现A接口的实现类都是不确定的,由于在方法未被调用之前是不确定传入参数的,所以此时添加元素操作会报编译时错误。

public void processElements(List<? extends A> elements){       for(A a : elements){      System.out.println(a.getValue());   }    }

这个时候可以把List,List或者List类型的变量作为参数传入processElements()方法之中,都是合法的。

List<A> listA = new ArrayList<A>();processElements(listA);List<B> listB = new ArrayList<B>();processElements(listB);List<C> listC = new ArrayList<C>();processElements(listC);

4 - 固定下边界的通配符:<? super E>

  • 使用固定下边界的通配符的泛型,就能够接受指定类及其父类类型的数据。
  • List<? super A> 的意思是List集合 list,它可以持有 A 及其父类的实例。
  • 当你知道集合里所持有的元素类型都是A及其父类的时候,此时往list集合里面插入A及其子类(B或C)是安全的(安全的向上转型),下面是一个实例Demo:

在读取list集合中元素的时候,只能选择用Object类型变量进行读取,因为读取任何元素虽然是不确定的(可能是A类本身或者它的父类),但是肯定都是Object。

Object object = list.get(0);
public static void insertElements(List<? super A> list){   list.add(new A());   list.add(new B());   list.add(new C());}

传入的List集合里的元素要么是A的实例,要么是A父类的实例,因为B和C都继承于A,如果A有一个父类,那么这个父类同时也是B和C的父类。

你可以往insertElements传入List或者一个持有A的父类的list。所以下面的例子是合法的:

/*因为此时我们可以确定传入的list集合里的元素是A及其父类,所以我们往这个集合里插入A及其子类是兼容的(向上转型)。*/List<A> listA = new ArrayList<A>();insertElements(listA);List<Object> listObject = new ArrayList<Object>();insertElements(listObject);

5 - 如何理解边界

  • 上述所谓的固定上下边界的理解:按照继承关系图,父类一定位于子类的上面,子类也一定位于父类的下面,所以<? extends E>就是固定上边界E,<? super E>就是固定下边界E。

注意:不能同时为一个泛型指定上下边界,只能指定上边界或下边界。

6 - 通配符使用原则

我们要记住这么几个使用原则,有人将其称为 PECS(Producer Extends, Consumer Super)原则,翻译过来就是 “生产者使用 extends,消费者使用 super”,我觉得还是不翻译的好。也有的地方写作 “in out” 原则,总的来说就是:

  • in 或者 producer 就是你要读取出数据以供随后使用(想象一下 List 的 get),这时使用 extends 关键字,固定上边界的通配符。你可以将该对象当做一个只读对象;
  • out 或者 consumer 就是你要将已有的数据写入对象(想象一下 List 的 add),这时使用 super 关键字,固定下边界的通配符。你可以将该对象当做一个只能写入的对象;
  • 当你希望 in 或 producer 的数据能够使用 Object 类中的方法访问时, 使用无边界通配符;
  • 当你需要一个既能读又能写的对象时,就不要使用通配符了。

(八)什么情况下不能使用泛型?

1 - 基本类型无法直接使用泛型

//这种写法是错的Map<int,char> wrong= new HashMap<>()
//需要用对应基本类型的包装类Map<Integer,Character> wrong= new HashMap<>()

2 - 泛型类型不能被实例化

泛型类型只不过是一种抽象的类型,仅仅代表类的抽象,因此不能直接实例化。

public <E> E getFirst(List<E> list){    E e = new E();//错误    return list.get(0);}

4 - 泛型无法持有静态类型

Java中的静态类型(static修饰的代码块、方法、变量、内部类、接口内方法)是随着类加载而进行初始化的,而泛型实际类型确定得创建对象的时候确定,所以泛型不能持有静态类型,否则必然报错,因为此时类加载的时候在静态方法中发现有不确定的类型。

public class Generic<T>{    // 不能将类声明的泛型类型作为静态变量    public static T t;    // 不能将类声明的泛型类型带入静态方法    public static T getFirst(List<T> list){        return list.get(0);    }    }
  • 注意:静态的泛型方法是可以的,是Java的一个规定。(博主一度查找了不少东西,也没有一个像样的理由,有知道的大佬欢迎评论)
public static <E> List<E> copyFromArrayToList(E[] arr){    ArrayList<E> list = new ArrayList<>();    for(E e : arr){        list.add(e);    }    return list;}

5 - 泛型无法进行instanceof判断

instanceof: instanceof关键字的作用是判断左边对象是否是右边类(这里有很多人说是对象,所以注意这里是类,并不是对象)的实例(通俗易懂的说就是:子类对象,或者右边类本身的对象),返回true或false。

  • instanceof关键字不能用于判断泛型,由于Java泛型的擦除机制,Java编译器在生成字节码的时候会擦除所有相关泛型的类型信息,如下例:当ArrayList<>带泛型的对象作为参数传入函数时(函数形参声明为List接口,因为接口不能实例化,所以传入参数的时候一定是具体实现类的对象,这也是Java面向对象的多态特性),由于JVM擦除了泛型,无法区分泛型不同的ArrayList,所以Java语言为了禁止这种instanceof貌似失去了它本来能实现的功能的这种现象的发生,就会在编译时报Error:Illegal generic type for instanceof
public static <E> void instanceOf(List<E> list) {    // Error:Illegal generic type for instanceof    if (list instanceof ArrayList<Integer>) {       }}

JVM擦除后:

public static void instanceOf(List list){  if(list instanceof ArrayList){  }}

思考:如何解决这种Error?(提示:利用通配符<?>)

6 - 泛型数组不合法

//以下两种都是不合法的//编译器报错:Generic array creationList<String>[] list = new ArrayList<String>[10]; Map<Integer,String>[] map = new HashMap<Integer,String>[10];
  • 如果不规定的话,将引发下面的逻辑错误:
Object[] stringLists = new List<String>[];  //擦除机制 --> List//放入String泛型的ArrayList对象stringLists[0] = new ArrayList<String>();   //放入Integer泛型的ArrayList对象stringLists[1] = new ArrayList<Integer>();//这显然不合理

(九)参考资料

  • https://developer.aliyun.com/article/640124
  • https://blog.csdn.net/briblue/article/details/76736356
  • https://www.hollischuang.com/archives/226
  • https://zhuanlan.zhihu.com/p/258891522
  • https://blog.csdn.net/qq_36835560/article/details/94022936

最后的最后

我是一个热爱IT技术和音乐的Dream Catcher,正在努力培养计算机的深度和广度认知,也会和大家伙儿分享我的音乐,大家伙儿多多关照 (๑❛ᴗ❛๑)
联系我的话,可以邮箱或者私信哦!!谢谢大家咯(*≧▽≦)
My Social Link:
我的个人博客站:https://blog.calvinhaynes.top/
我的知乎主页:https://www.zhihu.com/people/eternally-92-61
我的B站主页:https://space.bilibili.com/434604897
我的CSDN主页:https://blog.csdn.net/qq_45772333
我的邮箱:chx1006488386@163.com
我的Github主页:https://github.com/CalvinHaynes
我的码云主页:https://gitee.com/CalvinHaynes

喜欢我的文章的话,不妨留下你的大拇指,点个赞再走,您的支持是我创作的最大动力,也欢迎指正博客中存在的问题,谢谢呐(~ ̄▽ ̄)~

Java学习笔记(六):Java泛型相关推荐

  1. Java学习笔记 六、面向对象编程中级部分

    Java学习笔记 六.面向对象编程中级部分 包 包的注意事项和使用细节 访问修饰符 访问修饰符的注意事项和使用细节 面向对象编程三大特征 封装 封装的实现步骤(三步) 继承 继承的细节问题 继承的本质 ...

  2. Java学习笔记1:Java中有关print、println、printf的用法和区别

    Java学习笔记1:Java中有关print.println.printf的用法和区别 最近在学习java,写一些笔记记录下. 1.print()函数是一般的标准输出,但是不换行. 2.println ...

  3. Java学习笔记(java基础)

    Java学习笔记(第一周) Java 介绍 Java 发展方向 JVM , JDK , JRE 名词解释 Java语言的特点 Java安装 安装包的下载 配置环境变量 验证是否安装成功 Java的第一 ...

  4. 泛型java实例_【Java学习笔记】Java6泛型实例

    你若是不使用泛型,则会这样处理数据类型不确定的问题: class Stash { private Object x; void set(Object x) { this.x = x; } Object ...

  5. 【java】java学习笔记之java oop(面向对象)

    如下图所示为笔者总结的java oop(面向对象)学习笔记,其中,附带有代码示例(未展开),方便理解记忆.需要源文件的请到我的资源中下载,下载地址:https://download.csdn.net/ ...

  6. 【java】java学习笔记之java常用类

    如下图所示为笔者总结的java常用类学习笔记,其中,附带有代码示例(未展开),方便理解记忆.需要源文件的请到我的资源中下载,下载地址:https://download.csdn.net/downloa ...

  7. Java学习笔记-7.Java IO流

    一.输入/输出流 1.流:不同类型的输入.输出源    数据流:输入或输出的数据 Java数据流的所有接口和类都是在java.io包中定义的,因此应在程序开头加入 import java.io.* 2 ...

  8. Java学习笔记 - 4 Java核心类库

    4 Java 核心类库 4.1 泛型 泛型,即"参数化类型".就是将原来具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时 ...

  9. Java 学习笔记(4)——java 常见类

    上次提前说了java中的面向对象,主要是为了使用这些常见类做打算,毕竟Java中一切都是对象,要使用一些系统提供的功能必须得通过类对象调用方法.其实Java相比于C来说强大的另一个原因是Java中提供 ...

  10. java学习笔记(一) ----java下常用的包功能

    ***java下常用的包*** java.lang----包含一些java语言的核心类,如String,Math,Integer,System,Thread,提供常用的功能. java.awt---- ...

最新文章

  1. YTU 2610: A改错题--体检情况分析
  2. c#爬虫-1688官网自动以图搜图
  3. Zeppelin介绍
  4. C# 海康DVR客户端开发系列(2)—— 封装API (1)
  5. 获取字符串全排列 或者 只输出k个的组合
  6. Windows常用运行库合集--官网(VC++、DirectX、.NET)
  7. 最新kali之arping
  8. 使用win10自带的计算器,计算对数log
  9. dB、dBm、dBw、dBμV、dBmV、dBV、dBv等单位介绍
  10. DataWhale-动手数据分析-Task01:数据加载及探索性数据分析
  11. blackscholes matlab,基于MATLAB的Black-Scholes-Merton欧式期权定价模型的计算研究
  12. 分类刷题:A1008乘电梯
  13. 钉钉导航栏分享按钮的显示/隐藏
  14. 仿微博视频边下边播之封装播放器
  15. “秘密入职”字节跳动,百度高级经理一审被判赔107万
  16. 能够改变一生的5句话
  17. 【揭秘】1024特企- 前端仔微信里都藏着什么
  18. Linux 启动jar项目相关命令(解决关闭Linux终端,程序自动停止问题)
  19. 忘记密码怎么办,密码查看器X-pass
  20. 抓住中国势能 三星的“脱胎换骨”

热门文章

  1. HDU4699 Editor(双栈对弹)
  2. TFTP文件传输NFS挂载ARM开发板移植Linux系统步骤
  3. 02_安装nginx-银河麒麟V10(Kylin Linux Advanced Server V10 (Tercel))操作系统
  4. Linux查看及测试网络
  5. vue3和vue2中mian.js的区别,在其中配置路由为例
  6. 超滤膜助力料酒生产 美味十里飘香
  7. windows无法访问 计算机打印机,windows无法打开添加打印机解决方法
  8. 信号的频谱分析实验matlab,实验三 用FFT对信号进行频谱分析及MATLAB程序
  9. 高效实现斐波那契数列(Fibonacci数列)
  10. c语言学生班级通讯录,C语言做学生通讯录