想实现一个类存储数据,存储时可以像数组一样有数据的顺序,可以有下标方便获取数据 还可以无限存储,可修改可删除。
import java.util.Arrays;
/*
* @author jun
*
*/
public class MyList<T> {
// 最终存储数据的还是数组
T[] arr;
int index = 0;
public MyList() {
arr = (T[]) new Object[5];
}
/**
* 添加元素
* @param t
*/
public void add(T t) {
//判断是否超出数组长度,如果是则扩大长度
if (index == arr.length) {
arr = Arrays.copyOf(arr, arr.length + 5);
}
arr[index++] = t;
}
public T get(int i) {
return arr[i];
}
/**
* 显示
*/
public void show() {
StringBuffer str = new StringBuffer();
for (int i = 0; i < index; i++) {
if (i == index - 1) {
str.append(arr[i]);
} else {
str.append(arr[i] + ",");
}
}
System.out.println(str.toString());
}
/**
* 修改
* @param i
* @param t
*/
public void alter(int i, T t) {
arr[i] = t;
}
/**
* 刪除
* @param i
*/
public void delete(int i) {
for (; i < (index - 1); i++) {
if (i + 2 == index) {
arr[i + 1] = null;
} else {
arr[i] = arr[i + 1];
}
}
index--;
}
public static void main(String[] args) {
MyList<Object> list = new MyList<Object>();
list.add("1");
list.add(null);
list.add("hellow");
list.add(1);
list.add(new MyList());
list.add(new int[2]);
list.add("1");
list.show();
System.out.println(list.get(4));
list.delete(4);
list.alter(1, 6);
list.show();
}
}
一、泛型:
- 泛指的类型,可以代表任意类的
可以在类的后面指定泛型 public class 类名<泛型>
在类上面定义了泛型后,可以在当前类中的任意的位置使用当前的泛型,可以用在属性的类型、参数的类型、方法的返回值等等。
当我们创建一个泛型类的对象时,需要给泛型指定具体的类型,例:声明泛型
类名<具体类型(任何引用数据类型)> 对象 = new 类名<具体类型>();例:声明泛型
当指定了具体的类型时,那么类中所有的泛型都变成指定的类型
在创建对象时如果没有指定泛型的类型,那么泛型默认为Object类型
类名 对象 = new 类名(); -->Object
声明泛型
class Point<T> { // 此处可以是任意的标识符号,T是type的简称
private T var; // 此变量的类型由外部决定
public T getVar() { // 返回值的类型由外部指定
return var;
}
public void setVar(T var) {// 设置的类型由外部指定
this.var = var;
}
}
public class Test {
public static void main(String[] args) {
Point<Integer> p = new Point<Integer>(); // 里面的var类型为Integer类型
p.setVar(30); // 设置数字,自动装箱
System.out.println(p.getVar() * 2); // 计算结果,按数字取出
}
}
}
二、泛型设置的要求
在泛型的指定中,是无法指定基本数据类型的,必须设置成一个类,这样在设 置一个数字的时候就必须使用包装类,而在JDK 1.5之后提供了自动装箱的操 作,操作时也不会太复杂。
三、指定多个泛型
如果一个类中有多个属性需要使用不同的泛型声明,则可以在声明类的时候指 定多个泛型类型。
class Notepad<K,V> { // 此处指定两个泛型类型
private K key; // 此变量的类型由外部决定
private V value; // 此变量的类型由外部决定
public K getKey() {
return key;
}
public void setKey(K key) {
this.key = key;
}
public V getValue() {
return value;
}
public void setValue(V value) {
this.value = value;
}
}
四、泛型的应用
1、泛型应用中的构造方法
- 构造方法可以为类中的属性初始化,那么如果类中的属性通过泛型指定,而又 需要通过构造设置属性内容的时候,那么构造方法的定义与之前并无不同,不 需要像声明类那样指定泛型。
- 使用格式:
[访问权限] 构造方法 ([<泛型类型> 参数名称]){}
2、匹配任意类型的他通配符
- 在开发中对象的引用传递是最常见的,但是如果在泛型类的操作中,在进行引 用传递的时候泛型类型必须匹配才可以传递,否则是无法传递的。
class Info<T> {
private String var;
public String getVar() {
return var;
}
public void setVar(String var) {
this.var = var;
}
}
public class Test {
public static void main(String[] args) {
Info<String> i = new Info<String>(); // 指定String为泛型类型
i.setVar("lisi"); // 设置字符串
fun(i); // 错误,无法传递 应传指定Object为泛型类型
}
public static void fun(Info<Object> temp){// 此处可以接收Object泛型类型的 Info对象
System. out.println("内容:" + temp);
}
}
3、使用通配符“?”
- 以下程序在fun()方法中使用“Info<?>”的代码形式,表示可以使用任意的泛型类型对象,这 样做的话fun()方法定义的就比较合理了,但是在使用以上语法的时候也有一个注意点,即: 如果使用“?”接收泛型对象的时候,则不能设置被泛型指定的内容
class Info<T> {
private String var;
public String getVar() {
return var;
}
public void setVar(String var) {
this.var = var;
}
}
public class Test {
public static void main(String[] args) {
Info<String> i = new Info<String>() ; // 指定String为泛型类型
i.setVar("lisi") ; // 设置字符串
fun(i) ; // 传递 String为泛型类型
}
public static void fun(Info<?> temp){// 此处可以接收任意泛型类型的 Info对象
System.out.println("内容:" + temp.getVar());
}
}
4、受限泛型
- 在引用传递中,泛型操作中也可以设置一个泛型对象的范围上限和范围下限。 范围上限使用extends关键字声明,表示参数化的类型可能是所指定的类型, 或者是此类型的子类,而范围下限使用super进行声明,表示参数化的类型可 能是所指定的类型,或者是此类型的父类型,直至Object类。
- 设置上限:
声明对象:类名称<? extends 类> 对象名称
定义类:[访问权限] 类名称<泛型标识 extends 类>{}
设置下限:
声明对象:类名称<? super 类> 对象名称
定义类:[访问权限] 类名称<泛型标识 extends 类>{}
* 注意
一个类的子类可以通过对象多态性,为其父类实例化,但是在泛型操作中,子 类的泛型类型是无法使用父类的泛型类型接收,例如:Info 不能使 用Info
5、定义泛型接口
- 在JDK 1.5之后,不仅仅可以声明泛型类,也可以声明泛型接口,声明泛型接 口和声明泛型类的语法类似,也是在接口名称后面加上,如下格式所示:
- [访问权限] interface 接口名称<泛型标识>{}
interface Info<T>{ // 在接口上定义泛型
public T getVar() ;
}
- 泛型接口的两种实现方式
泛型接口定义完成之后,下面就要定义此接口的子类,定义泛型接口的子类时 有两种方式,一种是直接在子类之后声明泛型,另外一种是直接在子类实现的 接口中明确的给出泛型类型。 - 实现1 ——— 在子类的定义上声明泛型类型
interface Info<T>{ // 在接口上定义泛型
public T getVar() ;
}
class InfoImpl<T> implements Info<T>{// 定义泛型接口的子类
private T var; // 定义属性
public InfoImpl(T var){ // 通过构造方法设置属性内容
this.setVar(var);
}
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
}
- 实现2 ——— 直接在接口中指定具体类型
interface Info<T>{ // 在接口上定义泛型
public T getVar() ;
}
class InfoImpl implements Info<String>{// 定义泛型接口的子类,指定类型为String
private String var ; // 定义属性
public InfoImpl(String var){// 通过构造方法设置属性内容
this.setVar(var) ;
}
public void setVar(String var){
this.var = var ;
}
public String getVar(){ // 接口上已指明类型,所以此处必须是String
return this.var ;
}
}
6、定义泛型方法
- 泛型方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型,使用 如下的格式定义泛型方法。
- 泛型方法的简单定义:
[访问权限] <泛型标识> 返回值类型 方法名称([泛型标识 参数名称]) - 通过泛型方法返回泛型类实例
如果现在希望可以通过泛型方法返回一个泛型类的实例化对象的话,则必须在 方法的返回类型声明处明确的指定泛型标识。 - 使用泛型统一传入的参数类型
class Info<T> {
private T var; // 此变量的类型由外部决定
public T getVar() { // 返回值的类型由外部指定
return var;
}
public void setVar(T var) {// 设置的类型由外部指定
this.var = var;
}
public String toString() { // 覆写Object类中的toString()方法
return this.var.toString();
}
}
public class Test {
public static void main(String args[]) {
Info<String> i1 = new Info<String>(); // 设置String为泛型类型
Info<String> i2 = new Info<String>(); // 设置String为泛型类型
i1.setVar("HELLO"); // 设置内容
i2.setVar("lisi"); // 设置内容
add(i1, i2);
}
public static <T> void add(Info<T> i1, Info<T> i2) {
System.out.println(i1.getVar() + " " + i2.getVar());
}
}
7、泛型数组
- 使用泛型方法时,也可以传递或返回一个泛型数组,如下代码所示。
public class Test {
public static void main(String args[]) {
Integer i[] = fun1(1, 2, 3, 4, 5, 6); // 返回泛型数组
fun2(i); // 输出数组内容
}
public static <T> T[] fun1(T... arg) { // 接收可变参数,返回泛型数组
return arg; // 返回泛型数组
}
public static <T> void fun2(T param[]) { // 接收泛型数组
System.out.print("接收泛型数组:");
for (T t : param) {
System.out.print(t + "、");
}
System.out.println();
}
}
8、泛型的嵌套设置
- 可以在一个类的泛型中指定另外一个类的泛型。
class Info<T, V> {// 指定两个泛型类型
T string;
V i;
public Info(T string, V i) {
this.string = string;
this.i = i;
}
public T getValue() {
return string;
}
public V getVar() {
return i;
}
}
class Demo<S> {
S i;
public Demo(S i) {
this.i = i;
}
public S getInfo() {
return i;
}
}
public class Test {
public static void main(String args[]) {
Demo<Info<String, Integer>> d = null;// 将Info作为Demo的泛型类型
Info<String, Integer> i = null;// Info要指定两个泛型类型
i = new Info<String, Integer>("李四", 30);
d = new Demo<Info<String, Integer>>(i);// 在Demo类中设置Info类对象
System.out.println("内容一:" + d.getInfo().getVar());
System.out.println("内容二:" + d.getInfo().getValue());
}
}