一: 一个元组类库
1. 什么是元组
- 元组能做什么
调用一次方法能够返回多个对象 - 元组特性:
元组可以是任意长度,元组中的长度可以是任意类型 - 实现元组
定义泛型类,通过继承机制实现长度更长的元组
类的属性定义为final是出于安全考虑,外部类不能随意修改 - 实例
package com;
class Automobile{};
class cx<A,B>{
public final A a;
public final B b;
protected cx(A a,B b)
{
this.a=a;
this.b=b;
}
public A getA() {
return a;
}
public B getB() {
return b;
}
public String toString()
{
return "("+a+","+b+")";
}
}
class cx_a<A,B,C> extends cx<A,B>
{
public final C c;
public C getC() {
return c;
}
public cx_a(A a, B b,C c) {
super(a, b);
this.c=c;
// TODO Auto-generated constructor stub
}
public String toString()
{
return "("+a+","+b+","+c+")";
}
}
class cx_b<A,B,C,D> extends cx_a<A,B,C>
{
public final D d;
public cx_b(A a,B b,C c,D d)
{
super(a,b,c);
this.d=d;
}
public D getD() {
return d;
}
public String toString()
{
return "("+a+","+b+","+c+","+d+")";
}
}
public class test<A,B,C,D,E> extends cx_b<A,B,C,D>
{
private final E e;
public test(A a,B b,C c,D d,E e)
{
super(a,b,c,d);
this.e=e;
}
public E getE() {
return e;
}
public String toString()
{
return "("+a+","+b+","+c+","+d+","+e+")";
}
public static void main(String[] args) {
test<String,Integer,String,String,Long> temp=new test<String,Integer,String,String,Long>("a",3,"b","c",(long) 345);
System.out.println(temp.toString());
}
}
二:一个堆栈类
用LinkedList可以实现栈,这里我们不用LinkedList,采用内部链式存储机制来实现、
Node(3,top)其中的top是Node(2,top)
Node(2,top)其中的top是Node(1,top)
public class LinkedStack<T> {
private static class Node<U> {
U item;
Node<U> next;
Node() { item = null; next = null; }
Node(U item, Node<U> next) {
this.item = item;
this.next = next;
}
boolean end() { return item == null && next == null; }
}
private Node<T> top = new Node<T>(); // End sentinel
public void push(T item) {
top = new Node<T>(item, top);
}
public T pop() {
T result = top.item;
if(!top.end())
top = top.next;
return result;
}
public static void main(String[] args) {
// LinkedStack<String> lss = new LinkedStack<String>();
// for(String s : "Phasers on stun!".split(" "))
// lss.push(s);
// String ss;
// while((ss = lss.pop()) != null)
// System.out.println(ss);
//----- if put integer into the LinkedList
LinkedStack<Integer> lii = new LinkedStack<Integer>();
for(Integer i = 0; i < 10; i++){
lii.push(i);
}
Integer end;
while((end = lii.pop()) != null)
System.out.println(end);
//----- integer test end!
}
}
三:RandomList
class RandomList<T> {
private ArrayList<T> storage = new ArrayList<T>();
private Random rand = new Random(47);
public void add(T item) { storage.add(item); }
public T select() {
return storage.get(rand.nextInt(storage.size()));
}
public static void main(String[] args) {
RandomList<String> rs = new RandomList<String>();
for(String s: ("The quick brown fox jumped over " +
"the lazy brown dog").split(" "))
rs.add(s);
for(int i = 0; i < 11; i++)
System.out.print(rs.select() + " ");
}
}
四:泛型接口
package generics;
import java.util.Iterator;
import java.util.Random;
interface Generator<T> {
T next();
}
// 方法next()的返回类型是参数化的T。正如你所见到的,接口使用泛型与类使用泛型没什么区别。
// 为了演示如何实现Generator接口,我们还需要一些别的类。例如,Coffee类层次结构如下:
// Java代码 收藏代码
class Coffee {
private static long counter;// 编号,初始值为0
private final long id = counter++;
public String toString() {
return getClass().getSimpleName() + " " + id;
}
}
class Mocha extends Coffee {
}
class Latte extends Coffee {
}
class Breve extends Coffee {
}
// 现在,我们可以编写一个类,实现Generator<Coffee>接口,它能够随机生成不同类型的Coffee对象:
// Java代码 收藏代码
public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> {
private Class[] types = { Latte.class, Mocha.class, Breve.class, };
private static Random rand = new Random(47);
public CoffeeGenerator() {
}
// 为了使用For循环对该类实例进行迭代时次数控制:
private int size = 0;
public CoffeeGenerator(int sz) {
size = sz;
}
public Coffee next() {
try {
// 随机返回一个Coffee实例
return (Coffee) types[rand.nextInt(types.length)].newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 实现Iterator接口,这里属于黑箱迭代子模式
private class CoffeeIterator implements Iterator<Coffee> {
int count = size;
public boolean hasNext() {
return count > 0;
}
public Coffee next() {
count--;
// 调用外部类的next方法,所以前面要明确指定外部类类型,
// 不然的话就是调用内部类自身的方法了
return CoffeeGenerator.this.next();
}
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
// 向外界提供迭代器的实现,这样可以用在foreach循环语句中
public Iterator<Coffee> iterator() {
return new CoffeeIterator();
}
public static void main(String[] args) {
CoffeeGenerator gen = new CoffeeGenerator();
// 不使用迭代接口Iterator进行迭代时,由程序外部自己控制迭代过程
for (int i = 0; i < 5; i++) {
/*
* 某次输出: Breve 0 Breve 1 Mocha 2 Breve 3 Mocha 4
*/
System.out.println(gen.next());
}
/*
* 使用增加for循环,CoffeeGenerator实现了Iterable接口,所以它可以在
* 循环语句中使用。使用迭代子模式时迭代过程由迭代器来控制
*/
for (Coffee c : new CoffeeGenerator(5)) {
/*
* 某次输出: Breve 5 Mocha 6 Breve 7 Latte 8 Mocha 9
*/
System.out.println(c);
}
}
}
使用Generator<T>
接口生成斐波那契数列
public class Fibonacci implements Generator<Integer> {
protected int count = 0;//计数器
public Integer next() {
return fib(count++);//自动装箱
}
//递归求某数的斐波拉契
private int fib(int n) {
if (n < 2) {
return 1;
}
return fib(n - 2) + fib(n - 1);
}
public static void main(String[] args) {
Fibonacci gen = new Fibonacci();
//输出0-9的斐波拉契
for (int i = 0; i < 10; i++) {
/*
* Output: 1(0) 1(1) 2(2) 3(3) 5(4) 8(5) 13(6) 21(7) 34(8) 55(9)
*/
System.out.print(gen.next());
}
}
public int getIndex() {
return count - 1;
}
}
五:泛型方法
1.泛型方法比泛型类的优势之处:
(1)泛型方法使得方法能够独立于类而产生变化
(2)调用方法时调用static方法更方便,但是static方法无法访问泛型类的类型参数,所以如果static方法需要使用泛型能力,就必须成为泛型方法。
(3)使用泛型方法时通常不用指明参数类型(因为编译器会为我们找出具体的类型,这称为类型参数判断),而使用泛型类时必须在创建对象时指定类型参数的值
例:
//泛型方法
public class GenericMethods {
public <T> void f(T x){
System.out.println(x.getClass().getName());
}
public static void main(String[] args) {
GenericMethods gm = new GenericMethods();
gm.f("");
gm.f(1);
gm.f(1.0);
gm.f(1.0f);
gm.f(1.0f);
gm.f('c');
gm.f(gm);
}
}
2.杠杆利用类型参数推断
首先是一个静态方法:
class New1 {
public static <K, V> Map<K, V> map(){
return new HashMap<K, V>();
}
// 然后可以这样创建一个Map:
public static void test(String[] args){
Map<String, List<Cat>> catMap = New.map();
}
}
可以发现,右边的不用再按照以前的这种写法了:
Map<String, List> catMap = new HashMap<String, List>();
左边声明部分的类型为右边提供了一种推断,使得编译器可以直接创造出来具体的类了。不过,这种场景没有声明,直接使用New.map()是编译不通过的,因为没有像这里左边的可以推断的依据了, 如下面的,加入f()是一个方法,需要传入一个Map,如下的写法是编译不通过的:
f(New.map());
如果确实还是想按照上面那样使用,则可以考虑使用显示类型说明了,在操作符与方法名直接插入尖括号显示的指明类型,代码如下:
F(New.<Person, List>map());
不过这种方式很少使用。也就是说,在编写非赋值语句时,才要这样的说明,而使用不了杠杆利用类型推断。
我们为了方便,可以使用同样的方式创建其他的容器了,可惜JDK本身没有提供这样的类:
class New {
public static <K,V> Map<K,V> map() {
return new HashMap<K,V>();
}
public static <T> List<T> list() {
return new ArrayList<T>();
}
public static <T> LinkedList<T> lList() {
return new LinkedList<T>();
}
public static <T> Set<T> set() {
return new HashSet<T>();
}
public static <T> Queue<T> queue() {
return new LinkedList<T>();
}
// Examples:
public static void test(String[] args) {
Map<String, List<String>> sls = New.map();
List<String> ls = New.list();
LinkedList<String> lls = New.lList();
Set<String> ss = New.set();
Queue<String> qs = New.queue();
}
}
3.可变参数也是可以使用泛型声明类型的:
public class GenericVarargs {
public static <T> List<T> makeList(T... args){
List<T> result = new ArrayList<T>();
for(T item : args){
result.add(item);
}
return result;
}
public static void main(String[] args) {
List<String> ls = makeList("A");
System.out.println(ls);
ls = makeList("A","B","C");
System.out.println(ls);
ls = makeList("A","B","C","D","E");
System.out.println(ls);
}
}