java基础语法要点(基于1.8)

目录:

基本数据类型

数组

指针

运算符

String

接口

异常处理

多线程

枚举

注解(元数据)

I/O

泛型

lambda表达式

其他主题

内存管理

 

基本数据类型 8种  及对应的 类型封装器:

  byte, short, int, long ->  Long,Integer,Short,Byte :Number 

  float, double   ->  Double,Float :Number 

  char, boolean -> Character,Boolean

 1. java的其他方面是完全面向对象的,但基本数据类型不是,和c,c++一样,基本数据类型仅表示单个值,因为将基本数据类型设计为对象会极大地降低性能。

  类型封装器:基本类型提供了性能方面的好处,但有时会需要对象的表现形式:传递引用及许多数据结构都是针对对象进行操作的。   

     数值类型封装器都继承自抽象类Number

 2. 整型变化:

  • java的int总是32位,不随平台而变化。
  • 没有无符号整数,增加了“无符号右移”运算符。
  • 增加8位整型 byte,方便操作数据流及原始二进制数据。

 3. 字符型, char。

  • java使用unicode表示字符,char为16位(一个unicode标量的宽度)
  • 取值范围 0 ~ 65536
  • java中 char 同c 一样 可以做整型使用
    char ch1,ch2;
    
    ch1 = 88;
    
    ch2 = 'x';
    
    System.out.println(ch1);       // X
    
    System.out.println(ch2);	   // x
    
    System.out.println(++ch1);   // Y
    
    System.out.println(++ch2);   // y
    
    

     

  • java 中字符串类型 以对象形式出现,而不是如同c,c++那样作为字符数组。而在c#中string 是关键字,是String的别名,在java string没有被占用。
Integer(int num)

Integer(String str)   // NumberFormatException



Integer iob = new Integer(100);

int i = iob.intValue();



// 从jdk 5开始,增加了两个重要特性,自动装箱和自动拆箱。

// 极大地简化了一些算法代码,也有助于防止出错,对泛型,集合框架非常重要。



Integer iob = 100;

int i = iob;

 字面量0.56的类型是double,即浮点数的默认类型是double,而float 需要写作0.56f

同理1的类型是int

 

数组

 java中只有动态数组,同时会严格检查数组下标,避免越界。

 java中的数组是作为类的对象实现的。 

// 申请内存与c++相同,但无需delete操作

int x[] = new int[12];

       

// 也可以直接初始化,java会自动创建足够大的数组,以容纳数组初始化器里的元素

int days[] = {31,28,31,30,31,30,31};

       

// 多维数组

int twoD[][] = new int[4][5];



// 手动分配第二维

int twoD2[][] = new int[4][];

twoD2[0] = new int[1];

twoD2[1] = new int[2];

twoD2[2] = new int[3];

twoD2[3] = new int[4];



// 初始化器

int twoD3[][] = {

    	{1,2},

    	{1,2,3},

    	{1,2,3,4}

};

       

       

// 另一种数组声明语法

int[] y = new int[12]; //int x[] = new int[12];

int[][] twoD4 = new int[4][5];//twoD[][] = new int[4][5];

 在java中数组也是由类实现的,数组创建后如果没有初始化数据,则都会是默认值,即布尔类型默认为false,数值默认为0,其他默认为null。

 

指针

 java 中不支持程序员操作指针,因为指针可能突破java执行环境和宿主计算机之间的防火墙,操作java运行时系统之外的地址。这与java的设计理念不合。

 同时因为引用对象的变量的传递,实质是对指针的拷贝,所以java中没有真正的引用传递操作,因为JAVA认为没有指针也足够满足用户的需求。而c#中则可以使用ref。

public class test {

        // change不是在改变传入对象的状态,而是改了str的指向

	public static void change(String str){

		s = "aaa";

	}

	public static void main(String[] args) {

		// TODO Auto-generated method stub

		String s = "1223";

		change(s);

		System.out.println(s);

	}

}

// 结果: 1223, 证明其是值传递

  

运算符

 与c相比多出来的

>>>: 按位右移 补0 (对某些非数值的数据进行移位操作时,并不希望出现符号扩展)

instanceof      判别对象是否是某类的实例

布尔逻辑运算符:&,|,^,&=,|=, ^=   不短路的布尔逻辑运算

 

运算符分类 

算数运算符:

+,-,*, / , %, ++, --, +=,-=,*=,/=,%=

位运算符:

~,&,|,^,>>, >>>, <<, &=, |= , ^= , >>= , >>>=, <<=

关系运算符:

==,!=,>,<,>=,<=

布尔逻辑运算符:

&,|,^, ||, &&,!,&=,|=,^=,==,!=,?:

赋值运算符:

float a=3;

double b=2;



b+=a;

b=b+a;

a+=b;

a=a+b;  //报错, a+b时会自动把a提升为double,而double类型不能直接赋值给float

a=(float)(a+b)
// int类型的值 和 float类型的值相加,得到的结果是float而不是double

int a =1;

float b = 6;

b = b +a;

java里没有运算符重载,类的比较要用equals, 而不能用==,后者比较的是两个地址,即是恒等于

整型是会溢出的,所以有 i + 1< i 可能成立

同样 x>y||x<=y 也可能不成立

Double x = Double.NaN;

Float y = Float.NaN;

if(!(x>y||x<=y)){

	System.out.println("ok");

}

		

 

String:

 1. 每个字符串都是String的对象。

 2. 字符串对象是不可变的,修改字符串实际是创建了一个新的对象。

 3. 大量的字符串拼接操作,使用 StringBuffer和StringBuilder,它们是String的对等类,但它们允许修改字符串。

 4. 常用属性,方法: length, equals(), charAt()

 5. 命令行参数  main(String args[]){} 

class CommandLine{

    public static void main(String args[]){

        for(int i=0; i< args.length;i++){

            System.out.println("args["+i+"] : " + args[i]);

        }

    }

}



// java CommandLine this is a test 100 - 1

 

类 : 

  1. java中 未显式定义构造函数的类,编译器会自动添加默认构造器,将所有存储属性初始化为默认值。

      类的方法名也可以与类同名,因为方法有返回值,而构造函数的返回值是缺省的。

      创建类的实例,可以不用构造方法:

    比如调用对象的clone()方法,从内存上对已有对象的影印。

   运用反序列化手段,调用java.io.ObjectInputStream对象的 readObject()方法,是从文件中还原类的对象,也不会调用构造函数。

 

  2. java中没有析构函数,但提供了类似的finalize()方法。在回收类的对象时执行本方法。

  3. 访问控制public ,private, protected

  4. static, 静态变量的初始化如果需要计算,仅在第一次加载类时执行一次。

 在类被加载时static修饰的成员字段被初始化,与类关联,只要类存在,static字段就存在。一个static字段单独划分一块存储空间,不与具体的对象绑定在一起,该存储空间被类的各个对象所共享。

   区别: java中 静态变量和方法可以被实例对象调用(不推荐这样),而不像其他语言那样必须要用类名调用。// 即可以 this.*,而非必需Class.*

  5. final ,用于变量相当于const,用于方法则方法不可重写,用于类则类不可继承。

  6. 嵌套类, 内部类(非静态的嵌套类)。

  7. 可变参数 ,使用数组传递未知数量参数,需要手动将这些参数打包为数组,不仅繁琐,而且容易出错。所以有了可变参数的诞生,将封装数组的操作交给了编译器。

     void vaTest(int ... v){} // 与swift相比,省略号放在了前面。

   可变参数的方法存在模糊性(Ambiguous)

class test {

  void vaTest(int ... v){}

  void vaTest(boolean ... v){}

  void vaTest(int n, int ... v){}



   public static void main(String a[]){

       vaTest(1,2,3);

       vaTest(true);

       vaTest();  // Error,Ambiguous

       vaTest(1);// Error,Ambiguous

   }

}

 

继承:

 8. super 可以访问父类中被子类重写的属性和方法  super , this

    super.属性; //访问最近超类的属性

    super.方法   // 访问最近超类的方法 

    super();      //访问最近超类的构造函数

       构造函数 调用机制:在类层次中,从超类到子类按照继承的顺序调用构造函数。

     类A继承类B, 在实例化类A时,会先实例化类B,如果构造函数里有super(),则super()必须是子类构造函数中的第一条语句,而如果没有super(),那么也会先执行超类的默认构造函数或无参构造函数。 

class A{

	A(){

		System.out.println("init A");

	}

}



class  B extends A{

	B(){

		System.out.println("init B");

	}

	B(int x){

		System.out.println("init2 B");

	}

}



class C  extends B{

	C(){

		System.out.println("init C");

	}

	

	C(int x){

		System.out.println("init2 C");

	}

	C(boolean x){

		super(2);

		System.out.println("init3 C");

	}

}



class show2{

	public static void main(String args[]){

		C one = new C();

		/**

		 * init A

		 * init B

		 * init C

		 */

		

		C two = new C(1);

		/**

		 * init A

		 * init B

		 * init2 C

		 */

		

		C three = new C(true);

		/**

		 * init A

		 * init2 B

		 * init2 C

		 */

	}

}

 

 9.  方法重写

 java中没有虚函数,可以直接重写超类的方法。

class A{

	void callme(){

		System.out.println("A's callme method");

	}

}



class  B extends A{

	void callme(){

		System.out.println("B's callme method");

	}

}



class C  extends B{

	void callme(){

		super.callme();

		System.out.println("C's callme method");

	}

}



class show2{

	public static void main(String args[]){

		A a = new A();

		B b = new B();

		C c = new C();

		A r;

		

		r = a;

		r.callme();

		System.out.println("\n");

		

		r = b;

		r.callme();

		System.out.println("\n");

		

		r = c;

		r.callme();

	}

}

 10. 抽象类 ,abstract 

抽象类内部有一个抽象方法,需要显式地添加abstract修饰词,不能直接创建实例

abstract class ab{

	abstract void callme();

}

 11. final 阻止方法重写。

 1. 将方法声明为final ,有时可以提高性能。编译器可以自由地内联对这类方法的调用(当调用小的final方法时,编译器通常可以复制子例程的字节码,直接和调用方法的编译代码内联到一起。从而可以消除方法调用所需的开销。内联是final方法才有的选项。)。

   2 . 通常java在运行时动态分析对方法的调用,这称为后期绑定。而final 方法的调用却可以在编译时解析,这称为早期绑定

 final 阻止继承。 抽象类本身是不完整的,需要子类提供完整的实现,所以不能同时将类声明为abstract 和 final

 

Object类: java中所有其他类的超类,它的引用变量可以指向任何其他类的对象,包括数组。所有类的对象都可以使用Object类的方法。

     Object clone();   创建一个和将要复制的对象完全相同的新对象。

     boolean equals(Object objects); 判断一个对象是否和另一个对象相等。

     void finalize(); 在回首不再使用的对象之前使用

     final Class<?>getClass() 在运行时获取对象所属的类

     int hashCode() 返回与运行对象相关联的散列值

     final void notify()  恢复执行在调用对象上等待的某个线程

     final void notifyAll() 恢复执行在调用对象上等待的所有线程

     String toString() 返回一个描述对象的字符串

     final void wait()   等待另一个线程的执行

     final void wait(long milliseconds)

     final void wait(long milliseconds,int nanoseconds)

 

包 package

  包是多个类的容器,作用类似于命名空间。

  包是一种命名机制,也是一种可见性的控制机制,可以在包内定义包外部不能访问的类(不加访问修饰符)。

 访问控制

package p1;



public class Protection {

	int n = 1;

	private int n_pri = 2;

	protected int n_pro = 3;

	public int n_pub = 4;

	

	public Protection(){

		System.out.println("base constructor");

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

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

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

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

	}

}





package p1;



public class Derived extends Protection {

	Derived(){

		System.out.println("Derived constructor");

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

		// class only

		//System.out.println("n_pri = " + n_pri);

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

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

	}

}





package p1;



public class SamePackage {

	SamePackage(){

		Protection p = new Protection();

		

		System.out.println("SamePackage constructor");

		System.out.println("n = " + p.n);

		// class only

		//System.out.println("n_pri = " + p.n_pri);

		System.out.println("n_pro = " + p.n_pro);

		System.out.println("n_pub = " + p.n_pub);

	}

}





package p2;



import p1.Protection;



public class Protection2 extends Protection {

	Protection2(){

		System.out.println("Derived other package constructor");

		// class or package only

		//System.out.println("n = " + n);

		// class only

		//System.out.println("n_pri = " + n_pri);

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

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

	}

}





package p2;



public class otherPackage {

	otherPackage(){

		p1.Protection p = new p1.Protection();

		

		System.out.println("otherPackage constructor");

		// class or package only

		//System.out.println("n = " + p.n);

		// class only

		//System.out.println("n_pri = " + p.n_pri);

		// class,subclass or package only

		//System.out.println("n_pro = " + p.n_pro);

		System.out.println("n_pub = " + p.n_pub);

	}

}

导入包:

  import java.util.date;

  import java.io.*;

 

接口 interface  

   可声明为public 或 默认访问级别,也可以用abstract

  java将接口从其实现中完全抽象出来,接口与抽象类很像,但接口还有其他功能:一个类可以实现多个接口,但一个类只能继承一个超类。

  如果在类实现的两个接口中都声明了同一个方法,则这两个接口的客户都将可以使用这个方法。

实现接口的方法必须被声明为 public。

接口是对事物行为、属性的更高级别的抽象,放入接口中的全部都是不可变更的东西。同时接口是公开的,里面不能有私有的方法或变量。

   接口中没有实例变量,接口内的方法没有方法体。  

   接口中可以声明变量,它们会被隐式地标识为 final 和 static。 实现接口的类不能修改它们。

   接口中所有的变量和方法都被隐式地声明为 public。

interface CallBack{

	int x = 0;

	void  callback(int param);

}

   

 如果类包含了一个接口,但并没有实现该接口定义的全部方法,那么必须将类声明为抽象类

abstract class Incomplete implements CallBack {

     int a,b;

     void show {

         System.out.println(a + "  " + b);

    }

    // ...

}

 接口扩展接口

interface A{

    void method1();

}



interface B extends A{

    void method2();

}

接口中的变量

// 类似C 中的 #define 常量或 const 声明

// 如果接口不包含方法,那么实现该接口就相当于把接口中的常量导入到类名称空间中



import java.util.Random;



interface ShareConstants{

    int NO = 0;

    int YES = 1;

    int MAYBE = 2;

    int LATER = 3;

    int SOON = 4;

    int NEVER = 5;

}



class Question implements ShareConstants{

    Random rand = new Random();

    int ask(){

        int  prob = (int) (100 * rand.nextDouble());

        if (prob < 30) {

            // 在实例方法中直接使用静态变量,即可以 this.NO,而非必需Question.NO

             return NO;  // 30%

        }

        else  if (prob < 60) {

             return YES;  // 30%

        }

        else  if (prob < 75) {

             return LATER;  // 15%

        }

        else  if (prob < 98) {

             return SOON;  // 13%

        }

        else  {

             return NEVER;  // 2%

        }

    }

}



class AskMe implements ShareConstants{

     static void answer(int result){

           switch(result){

               case NO:

                    System.out.println("No");

                    break;

               case YES:

                    System.out.println("Yes");

                    break;

               case MAYBE:

                    System.out.println("Maybe");

                    break;

               case LATER:

                    System.out.println("Later");

                    break;

               case SOON:

                    System.out.println("Soon");

                    break;

               case NEVER:

                    System.out.println("Never");

                    break;

           }

     }



      public static void main(String a[]){

            Question q = new Question ();

            answer(q.ask());

            answer(q.ask());

            answer(q.ask());

            answer(q.ask());

            answer(q.ask());

      }

}

 

 嵌套接口 :将接口声明为某个类或另一个接口的成员。private,public, protected,或默认

// a nested interface example



class A{

	 //a nested interface

	public interface NestedIF{

		boolean isNotNegative(int x);

	}

}



class B implements A.NestedIF{

	public boolean isNotNegative(int x){

		return x < 0 ? false : true;

	}

}



class NestedDemo{

	public static void main(String args[]){

		A.NestedIF nif = new B();

		

		if (nif.isNotNegative(10))

			System.out.println("ssss");

	}

}

 

   jdk 8 为接口增加了一个新的特性,在jdk 8之前,接口只能定义“有什么”,而不能定义“如何实现”。

   从jdk 8开始,可以在接口方法中添加默认实现。然而,默认实现只是构成了一种特殊用途,接口最初的目的没有改变。

  接口添加默认实现的好处有:

    1.  提供了可选功能,接口方法 带有了默认实现,则实现该接口的类就不必在不需要该功能时提供占位符实现了。

    2.  可以优雅地随时间演变接口,当为一个广泛使用的接口添加一个新方法时,不必破环现有代码。

// 接口默认方法的定义类似于为类定义方法,区别在于,需带关键字default



public interface MyIF{

    int getNumber();



    default String getString(){

          return "Default String";

    }

}

 因为接口依然不能有实例变量。所以接口的特征没有改变,依然不能维护状态信息(这是接口和类的决定性区别)。

  所以默认方法的引入,只是带来了额外的灵活性。并未有C++那样的多重继承。

 但类确实可以从接口中继承一些行为,在一定程度上支持多重继承,也就可能发生名称冲突。

 解决办法:

  1. 在所有情况下,类实现的优先级高于接口的默认实现。类中的重写将覆盖接口中的默认方法,即便几个接口发生名称冲突,也会一起被重写。

  2. 当类实现的两个接口提供了相同的默认方法,但是类没有重写该方法时,则会发生错误。

  3. 如果一个接口继承了另一个接口,并且两个接口定义了相同的默认方法。那么继承接口的版本具有更高优先级。

 

 jdk 8 新增的另一个特性是,接口可以定义一个或多个静态方法。且接口定义的静态方法可以独立于任何对象调用。

 实现接口的类或子接口不会继承接口中的静态方法。

public interface MyIF{

    int getNumber();

    default String getString(){

         return "Default String ";

    }



    static int getDefaultNumber(){

         return 0;

    }

}



// 调用



int defNum =  MyIF.getDefaultNumber();

 

 

动态方法调度(运行时多态的基础),使用超类或接口,依赖倒置,有利于解偶,但要在运行时动态查找方法,性能上会增加额为负担。

所以在性能要求苛刻的代码中,应当谨慎小心。

 

异常处理

 在不支持异常处理的语言中,必须手动检查和处理错误,而java的异常处理避免了这些问题,并且在处理过程中采用面向对象的方式管理运行时错误。

java异常是用来描述在一段代码中发生的异常情况的对象。当出现引起异常的情况时,就会创建用于表示异常的对象,并在引起错误的方法中抛出异常对象,方法可以选择自己处理异常,也可以继续传递异常,无论采用哪种方式,在某一点都会捕获并处理异常,异常可以由java运行时系统生成,也可以通过代码手动生成,前者与那些违反java语言规则或java执行环境的基础性错误有关,后者通常用于向方法的调用者报告某些错误条件。

 

5个关键字: try ,catch , throw ,finally ,和  throws (java的检查型异常处理,c#中舍弃了)

jdk 7开始 try语句增加了一种支持自动资源管理的新形式,称为带资源的try。

 

所有异常都是内置类 Throwable的子类。

 紧跟Throwable之下的是两个子类,将异常分为两个不同的分支。

   Exception:既可以用于用户程序应当捕获的异常情况,也可以用于创建自定义的异常类型的子类。

         RuntimeException

   Error:定义了在常规环境下不希望由程序捕获的异常,由java运行时系统使用,以指示运行时环境本身出现了某种错误。如堆栈溢出。通常是为了响应灾难性的失败而创建。应用程序通常不处理这类异常。

Throwable 重写了 toString()方法,从而可以返回一个包含异常描述的字符串。

 

未捕获的异常:

  如果程序没有捕获异常,当Java运行时系统检测到错误操作时,它会构造一个新的异常对象,然后抛出,这会导致程序终止执行。

因为异常一旦抛出,就必须要有一个异常处理程序捕获该异常,并立即进行处理。如果程序员没有提供任何自己的异常处理程序,该异常就会由Java运行时系统提供的默认处理程序捕获,默认处理程序会显示一个描述异常的字符串,输出异常发生点的堆栈踪迹并终止程序。堆栈轨迹会显示导致错误的方法的调用序列,可以精确定位导致错误发生的步骤序列,帮助程序员调试。

 

程序员自己处理异常 try ... catch:

  1. 可以修复错误,2.阻止程序自动终止。

 大部分设计良好的catch子句,都应当能够分辨出异常情况,然后继续执行。

 

try-catch 语句由一个 try 块后跟一个或多个 catch 子句构成,这些子句指定不同的异常处理程序。引发异常时,运行时系统会查找处理此异常的 catch 语句。如果当前执行的方法不包含这样的 catch 块,则查看调用当前方法的方法,然后会遍历调用堆栈。如果找不到 catch 块,则 CLR 会向用户显示一条有关未处理异常的消息并停止执行程序。

 

使用多条catch语句时,异常子类必须位于所有超类之前。否则会编译错误 “Unreachable catch block”

public class test {

    public static void main(String args[]){

    	try{

    		try{

            	

            	

//            	int a = args.length;

//            	System.out.println("a = " + a);

//            	int b = 42 / a;

//            	System.out.println(b);

//            	

            	int c[] ={1};

            	c[42] = 99;

            	

            	throw new NullPointerException("demo");

            	

            }

            catch(ArithmeticException e){

            	System.out.println("Divide by 0:" + e);

            }

            catch(ArrayIndexOutOfBoundsException e){

            	System.out.println("Array index oob:"+ e);

            }

    		finally{

    			System.out.println("finally");

    		}

            System.out.println("after");

    	}

    	catch(Exception e){

    		System.out.println("Exception:"+ e);

    	}

  }

}

throws:

 如果方法可能引发自身不进行处理的异常,就必须指明这种行为,以便方法的调用者能够防备这些异常。 throws子句列出了方法可能抛出的异常类型。

除了Error和 RuntimeExceptin 及其子类类型,对于所有其他类型的异常都必需这样处理。

package throwsDemo;



public class ThrowsDemo {

	public static void main(String args[]){

		try {

			throwOne();

		} catch (IllegalAccessException e) {

			// TODO Auto-generated catch block

			e.printStackTrace();

		}

	}

    static void throwOne() throws IllegalAccessException{

		System.out.println("Inside throwOne");

		throw new IllegalAccessException("demo");

	}

}

 在java.lang中,Java定义了一些异常类,这些异常类中最常用的是RuntimeException的子类。这些异常不需要包含在方法的throws列表中

异常 含义
ArithmeticException 算术错误,例如除0
ArrayIndexOutOfBoundsException 数组索引越界
ArrayStoreExcepion 使用不兼容的类型为数组元素赋值
ClassCastException 无效转换
EnumConstantNotPresentException 使用未定义的枚举值
IllegalArgumentException 使用非法参数调用方法
IllegalMonitorStateException 非法的监视操作,例如等待未锁定的线程
IllegalThreadStateException 环境或应用程序处于不正确的状态
IndexOutOfBoundsException 某些类型的索引越界
NegativeArraySizeException 使用负数长度创建数组
NullPointerException 非法使用空引用
NumberFormatException 字符串到数值格式的无效转换
SecurityException 违反安全性
StringIndexOutOfBounds 字符串索引越界
TypeNotPresentException 类型未定义
UnsupportedOperationException 不支持的操作
ClassNotFoundException 类未定义
CloneNotSupportedException 试图复制没有实现Cloneable接口的对象
IllegalAccessException 对类的访问被拒绝
InstantiationException 试图实例化一个抽象类或接口
InterruptedException 一个线程被另一个线程中断
NotSuchFieldException 请求的域变量不存在
NotSuchMethodException 请求的方法不存在
ReflectiveOperationExcepton 与反射相关的异常的超类
   
   

 

public class ThrowsDemo {

	public static void main(String args[]){

		try{

		throwOne();

		}

		catch(Exception e){

			e.printStackTrace();

		}

	}

    static void throwOne(){

		System.out.println("Inside throwOne");

		throw new ClassCastException("demo");

	}

}

 

自定义异常

class MyException extends  Exception {

   private int detail;

   

   MyException(int a){

	   detail = a;

   }

   

   public String toString(){

	   return "MyException["+detail+"]";

   }

}



class ExceptionDemo{

	static void compute(int a) throws MyException{

		System.out.println("Called compute("+a+")");

		if (a>10){

			throw new MyException(a);

		}

		System.out.println("Normal exit");

	}

	

	public static void main(String args[]){

		try {

			compute(1);

			compute(20);

		} catch (MyException e) {

			// TODO Auto-generated catch block

			System.out.println("Caught: "+e);

		}

	}

}

 链式异常:从jdk1.4 开始,链式异常呗包含进入异常子系统。通过链式异常,可以为异常关联另一个异常。

   为了使用链式异常,Throwable 增加了两个构造函数和两个方法。

     为异常设置原因:

    Throwable(Throwable causeExc)

    Throwable(String msg, Throwable causeExc)

    Throwable initCause(Throwable causeExc)

     查询引发异常的原因:

    Throwable getCause()  // 返回引发当前异常的异常,如果没有则返回null 

public class ChainExcDemo {

	static void demoproc(){

		

		NullPointerException e = new NullPointerException("top layer");

		

		e.initCause(new ArithmeticException("cause"));

		

		throw e;

	}

	

	public static void main(String args[]){

		try{

			demoproc();

		}catch(NullPointerException e){

			System.out.println("Caught: " + e);

			System.out.println("Original cause: " + e.getCause());

		}

	}

}

 

 jdk 7 新增3个特性:

  1. 带资源的try,当资源不再需要时会自动释放。

  2. 多重捕获,允许通过相同的catch子句捕获多个异常,每个多重捕获参数都被隐式声明为final

public class MultiCatch {

	public static void main(String args[]){

		int a = 10,b = 0;

		int vals[] = {1,2,3};

		

		try{

			int result = a / b;

			vals[10] =19;

			

		}

		catch(ArithmeticException|ArrayIndexOutOfBoundsException e){

			System.out.println("Exception Caught:" + e);

		}

		System.out.println("after");

	}

}

3. 更精确地重新抛出 more precise rethrow(最后重新抛出 final rethrow)

 更精确地重新抛出 会对重新抛出的异常类型进行限制,只能重新抛出满足以下条件的经检查的异常:由关联的try代码块抛出,没有被前面的catch子句处理过,并且是参数的子类型或者超类型。 为了强制使用这一特性,catch参数须被有效地或者显式地声明为final

class FirstException extends Exception{

	FirstException(String s){

		super(s);

	}

}



class SecondException extends Exception{

	SecondException(String s){

		super(s);

	}

}



public class Rethrowing { 

	// f会抛出一个异常 

	public static void f(boolean a) throws FirstException, SecondException   { 

		 System.out.println("originating the exception in f()"); 

		 if(a){

			 throw new FirstException("thrown from f()"); 

		 }

		 else{

			 throw new SecondException("thrown from f()"); 

		 }

	} 

	

	// g中捕获f抛出的Exception异常并重新抛出

	

// 报错,更精确的异常抛出 catch子句中抛出的异常必须来自try代码块,否则编译器无法解析

// 这里 throws子句需改为 throws Exception,恢复为普通的重新抛出异常

//	public static void g() throws FirstException, SecondException { 

//		 try { 

//			 f(true); 

//		 } 

//		 catch(Exception e) { 	  

//		     System.out.println("Inside g(), e.printStackTrace()"); 

//		     

//		     // 如果e 被重新赋值为其他异常

//		     e= new FirstException("22");

//		     throw e; 

//		 }

//	}

	

	// 更精确的重新抛出

	// 即使 catch 子句的异常参数e的类型是 Exception,

	// 但 throws 子句中却可指定异常类型为  FirstException 和 SecondException。

	// Java SE 7编译器要求语句抛出的异常必须来自于 try 块,   

	// 并且 try 块抛出的异常只能是 FirstException 和 SecondException。

	public static void g()throws FirstException, SecondException{

		 try { 

			 f(true); 

		 } 

		 catch(final Exception e) { 	  

			 System.out.println("Inside g(), e.printStackTrace()"); 

			 throw e; 

		 }

	}

	

	public static void main(String[] args){ 

		try { 

			g(); 

		}

		catch(Exception e) { 

		    System.out.println("Caught in main, e.printStackTrace()"); 

		    e.printStackTrace(); 

		} 

	}

}

 

多线程:

 java内置支持多线程。多线程是特殊形式的多任务处理

 多线程程序包含同时运行的多个部分,每个部分被称为一个线程,并且每个线程定义了一个单独的执行路径。

 多任务处理 有两种类型: 基于进程和基于线程。

   进程本身是程序,基于进程的多任务处理就是允许计算机同时运行多个程序的特性。程序时调度程序的最小代码单元。

   而基于线程的多任务环境中,最小的可调度代码单元是线程。这意味着单个程序可以同时执行多个任务。

 

Thread类 和 Runnable接口

Thread作为线程代理,定义了一些管理线程的方法:

 getName(),getPriority(), isAlive(), join() /*等待线程终止*/, run()/*线程的入口点*/, sleep()/*线程挂起*/, start()/*调用线程的run()方法启动线程*/

 

1. 主线程: Thread.currentThread() (main/*默认名称*/,5/*优先级*/,main/*线程组*/)

    在java程序启动时,会立即开始运行的一个线程。

     其他子线程都是从主线程产生的。

   通常主线程必须是最后结束执行的线程,因为它要执行各种关闭操作。

public class CurrentThreadDemo {

	public static void  main(String args[]){

		Thread t = Thread.currentThread();

		System.out.println("Current thread: "+ t);

		

		t.setName("my thread");

		System.out.println("after name change: "+ t);

		

		try{

			for(int n= 5; n>0;n--){

				System.out.println(n);

				Thread.sleep(1000);

			}

		}

		catch(InterruptedException e){

			System.out.println("InterruptedException:"+ e);

		}

	}

}

 创建线程:

  java提供了两种方法: 实现Runnable接口,扩展Thread类 

实现Runnable接口:

  只需实现run方法,就像main线程一样,区别在于run方法为程序中另外一个并发线程的执行建立了一个入口点,当run方法返回时,这个线程将结束。

class NewThread implements Runnable {

	private Thread t;

	private String name;

	

	NewThread(String threadName){

		name = threadName;

		t = new Thread(this,threadName);

		System.out.println("Child thread:"+ t);

		t.start();

	}

	

	@Override

	public void run() {

		// TODO Auto-generated method stub

		try{

			for(int i =5; i>0;i--){

				System.out.println("Child thread "+name+":"+ i);

				Thread.sleep(500);

			}

		}

		catch(InterruptedException e){

			System.out.println("Child  "+name+"interrupted:"+ e);

		}

		System.out.println("Exiting child  "+name+"thread");

	}

}



class RunnableDemo {

	public static void main(String args[]){

		// 开启子线程

		new NewThread("a");

		new NewThread("b");

		new NewThread("c");

		

		try{

			for(int i=5;i>0;i--){

				System.out.println("Main thread:"+ i);

				Thread.sleep(1000);

			}

		}

		catch(InterruptedException e){

			System.out.println("Main interrupted:"+ e);

		}

		System.out.println("Exiting Main thread");

	}

	

}

 

 主线程必须在最后结束运行,因为对于某些旧的JVM,如果主线程在子线程完成之前结束,java运行时系统可能会挂起。

 

扩展Thread类:

class NewThread extends Thread{

	

	NewThread(){

		super("Demo Thread");

		System.out.println("Child Thread:"+this);

		start();

	}

	

	public void run(){

		try{

			for(int i =5; i>0;i--){

				System.out.println("Child thread:"+ i);

				Thread.sleep(500);

			}

		}

		catch(InterruptedException e){

			System.out.println("Child interrupted:"+ e);

		}

		System.out.println("Exiting child thread");

	}

}



public class EntendThread {

	public static void main(String args[]){

		// 开启子线程

		new NewThread();

		

		try{

			for(int i=5;i>0;i--){

				System.out.println("Main thread:"+ i);

				Thread.sleep(1000);

			}

		}

		catch(InterruptedException e){

			System.out.println("Main interrupted:"+ e);

		}

		System.out.println("Exiting Main thread");

	}

}

 join() 在主线程中执行子线程A.join(),则主线程会更这个子线程A执行完毕之后才会进行后续操作

class NewThread implements Runnable {

	Thread t;

	private String name;

	

	NewThread(String threadName){

		name = threadName;

		t = new Thread(this,threadName);

		System.out.println("Child thread:"+ t);

		t.start();

	}

	

	@Override

	public void run() {

		// TODO Auto-generated method stub

		try{

			for(int i =5; i>0;i--){

				System.out.println("Child thread "+name+":"+ i);

				Thread.sleep(500);

			}

		}

		catch(InterruptedException e){

			System.out.println("Child  "+name+"interrupted:"+ e);

		}

		System.out.println("Exiting child  "+name+"thread");

	}

}



class RunnableDemo {

	public static void main(String args[]){

		// 开启子线程

		NewThread A = new NewThread("a");

		NewThread B = new NewThread("b");

		NewThread C = new NewThread("c");

		

		System.out.println("thread a is alive:"+ A.t.isAlive());

		System.out.println("thread b is alive:"+ B.t.isAlive());

		System.out.println("thread c is alive:"+ C.t.isAlive());

		

		try{

			System.out.println("waiting for threads to finish");

			A.t.join();

			B.t.join();

			C.t.join();

			

			for(int i=5;i>0;i--){

				System.out.println("Main thread:"+ i);

				Thread.sleep(1000);

			}

		}

		catch(InterruptedException e){

			System.out.println("Main interrupted:"+ e);

		}

		

		System.out.println("thread a is alive:"+ A.t.isAlive());

		System.out.println("thread b is alive:"+ B.t.isAlive());

		System.out.println("thread c is alive:"+ C.t.isAlive());

		

		System.out.println("Exiting Main thread");

	}

	

}

 同步 

synchronized方法
class Callme{

	synchronized void call(String msg){

		System.out.print("["+msg);

		try{

			Thread.sleep(1000);

		}

		catch(InterruptedException e){

			System.out.println("InterruptedException");

		}

		System.out.println("]");

	}

}



class Caller implements Runnable{

	String msg;

	Callme target;

	Thread t;

	

	public Caller(Callme targ,String s){

		target= targ;

		msg =s;

		t = new Thread(this);

		t.start();

	}

	

	@Override

	public void run() {

		// TODO Auto-generated method stub

		target.call(msg);

	}

	

}



public class Synchronized {

	public static void main(String args[]){

		Callme target = new Callme();

		Caller ob1 = new Caller(target,"hello");

		Caller ob2 = new Caller(target,"Synchronized");

		Caller ob3 = new Caller(target,"world");

		

		try{

			ob1.t.join();

			ob2.t.join();

			ob3.t.join();

			

		}

		catch(InterruptedException e){

			System.out.println("InterruptedException");

		}

	}

}
synchronized 语句
class Callme{

	 void call(String msg){

		System.out.print("["+msg);

		try{

			Thread.sleep(1000);

		}

		catch(InterruptedException e){

			System.out.println("InterruptedException");

		}

		System.out.println("]");

	}

}



class Caller implements Runnable{

	String msg;

	Callme target;

	Thread t;

	

	public Caller(Callme targ,String s){

		target= targ;

		msg =s;

		t = new Thread(this);

		t.start();

	}

	

	@Override

	public void run() {

		// TODO Auto-generated method stub

		synchronized(target){

			target.call(msg);

		}

	}	

}



public class Synchronized {

	public static void main(String args[]){

		Callme target = new Callme();

		Caller ob1 = new Caller(target,"hello");

		Caller ob2 = new Caller(target,"Synchronized");

		Caller ob3 = new Caller(target,"world");

		

		try{

			ob1.t.join();

			ob2.t.join();

			ob3.t.join();

			

		}

		catch(InterruptedException e){

			System.out.println("InterruptedException");

		}

	}

}

 

多线程通过将任务分隔到独立的逻辑单元来替换事件循环编程,线程还提供了第二个优点:消除了轮询检测。

     为了避免轮询检测(通过重复检查某些条件的循环来判断是否执行某操作),java通过wait(),notify()及notifyAll() 提供了一种进程间通信机制。这三个方法只能在同步上下文中调用。

    wait() 方法通知调用线程放弃监视器并进入休眠。直到其他一些线程进入同一个监视器并调用notify()方法或notifyAll()方法。

    notify()方法唤醒调用相同对象的wait()中的线程。

    notifyAll() 方法唤醒调用相同对象的wait()中的所有线程,其中一个线程将得到访问授权。

    wait()方法有另一种形式,可以指定等待的时间间隔。因为线程有极小可能被假唤醒(没有调用notify,而线程被恢复),   所以应当在一个检查线程等待条件的循环中调用wait()

// 队列

class Q{

	int n;

	boolean valueSet = false;

	

	synchronized int get(){

		while(!valueSet){

			try{

				wait();

				

			}

			catch(InterruptedException e){

				System.out.println("InterruptedException");

			}

		}

		System.out.println("Got: "+ n);

		valueSet =false;

		notify();

		return n;

	}

	

	synchronized void put(int n){

		while(valueSet){

			try{

				wait();

				

			}

			catch(InterruptedException e){

				System.out.println("InterruptedException");

			}

		}

		this.n =n ;

		valueSet =true;

		System.out.println("Put: "+ n);

		notify();

	}

}



class Producter implements Runnable{

	Q q;

	

	Producter(Q q){

		this.q = q;

		new Thread(this,"Producter").start();

	}

	

	@Override

	public void run() {

		// TODO Auto-generated method stub

		int i = 0;

		while(i < 100){

			q.put(i++);

		}

	}

}





class Consumer implements Runnable{

	Q q;

	

	Consumer(Q q){

		this.q = q;

		new Thread(this,"Consumer").start();

	}

	

	@Override

	public void run() {

		// TODO Auto-generated method stub

		while(q.get() < 99){

		}

	}

}

public class Wait2Notify {

	public static void main(String args[]){

		Q q = new Q();

		new Producter(q);

		new Consumer(q);

	}

}

 死锁

 一个线程进入对象X的监视器,另一个线程进入对象Y的监视器,如果X中的线程试图调用对象Y的任何同步方法,那么都会被阻塞,需要等待当前占据对象Y的线程执行完毕,移出对象Y的监视器,而如果对象Y中的线程也试图调用对象X的任何同步方法,则会造成死锁。

class A{

	synchronized  void foo(B b){

		String name = Thread.currentThread().getName();

		System.out.println(name + " entered A.foo()");

		

		try{

			Thread.sleep(1000);

			

		}

		catch(Exception e){

			System.out.println("A Interrupted");

		}

		

		System.out.println(name +" trying to call B.last()");

		b.last();

	}

	

	synchronized void last(){

		System.out.println("Inside A.last()");

	}

}

class B{

	synchronized void bar(A a){

		String name = Thread.currentThread().getName();

		System.out.println(name + " entered B.bar()");

		

		try{

			Thread.sleep(1000);

			

		}

		catch(Exception e){

			System.out.println("B Interrupted");

		}

		

		System.out.println(name +" trying to call A.last()");

		a.last();

	}

	

	synchronized void last(){

		System.out.println("Inside B.last()");

	}

}

public class DeadLock implements Runnable {

	A a = new A();

	B b = new B();

	

	DeadLock(){

		Thread.currentThread().setName("MainThread");

		Thread t = new Thread(this,"RacingThread");

		t.start();

		

		a.foo(b);

		System.out.println("back in main thread");

	}

	

	public  void run(){

		b.bar(a);

		System.out.println("back in other thread");

	}

	

	public static void main(String args[]){

		new DeadLock();

	}

}

 挂起,恢复,停止

java 2以前,程序使用Thread类定义的suspend(),resume(),stop()方法。这些方法在java2不再使用的原因是:

  suspend()方法有时会导致严重的系统故障,假定线程为关键数据结构加锁,如果这是线程被挂起,那么这些锁将无法释放。其他可能等待这些资源的线程会被死锁。

  resume()与suspend()是配对使用的,所以也一起废弃。

  stop()方法有时也会造成严重的系统故障,假定线程正在向关键的重要数据结构中写入数据,并且只完成了部分发生变化的数据。如果这时停止线程,那么数据就够可能会处于损坏状态,问题是stop()会导致释放调用线程的所有锁,因此,另一个正在等待相同锁的线程可能会使用这些已损坏的数据。

所以现在面向函数编程开始流行,就是因为函数式编程不需要保存状态,也就不需要锁定,也就没有上述的各种状况。可以大大简化多线程操作的难度。

 

  现在,线程被设计为run()方法周期性进行检查,以确保是否应当挂起,恢复或停止线程自身的执行。

class NewThread implements Runnable{

	String name;

	Thread t;

	boolean suspendFlag;	

	

	NewThread(String threadName){

		name = threadName;

		t = new Thread(this,name);

		System.out.println("New Thread: "+ t);

		suspendFlag = false;

		t.start();

	}

	

	@Override

	public void run() {

		// TODO Auto-generated method stub

		try{

			for(int i = 15; i>0;i--){

				System.out.println(name +": "+ i);

				Thread.sleep(2000);

				synchronized(this){

					while(suspendFlag){

						wait();

					}

				}

			}

		}

		catch(InterruptedException e){

			System.out.println(name +" InterruptedException");

		}

		

		System.out.println(name +" exiting");

	}

	

	synchronized void mysuspend(){

		suspendFlag =true;

	}

	synchronized void myresume(){

		suspendFlag =false;

		notify();

	}

}



public class Mysuspend {

	public static void main(String args[]){

		NewThread ob1 = new NewThread("one");

		NewThread ob2 = new NewThread("two");

		

		try{

			Thread.sleep(1000);

			ob1.mysuspend();

			System.out.println("Suspending thread one");

			Thread.sleep(1000);

			ob1.myresume();

			System.out.println("Resuming thread one");

			

			ob2.mysuspend();

			System.out.println("Suspending thread two");

			Thread.sleep(1000);

			ob2.myresume();

			System.out.println("Resuming thread two");

		}

		catch(InterruptedException e){

			System.out.println("Main thread InterruptedException");

		}

		

		try{

			System.out.println("Waiting for threads to finish");

			ob1.t.join();

			ob2.t.join();

		}

		catch(InterruptedException e){

			System.out.println("Main thread InterruptedException");

		}

		

		System.out.println("Main thread exiting");

	}

}

 线程状态: if(t.getState()  == Thread.State.RUNNABLE)

 BLOCKED/*因为正在等待需要的锁儿挂起执行*/,

 NEW/*线程换没有开始执行*/,

 RUNNABLE/*线程要么当前正在运行,要么在获取cpu的访问权后执行*/,

 TERMINATED/*线程已经完成执行*/,

 TIMED_WAITING/*线程挂起执行一段指定的时间,如sleep(),暂停版的wait(),join()*/,

 WAITING/*线程因为某些动作而挂起执行,如调用非暂停版的wait(),join()*/

   

线程的上下文切换需要一定的开销,如果创建的线程太多,可能反而会降低程序的性能。 Fork/Join 框架创建可自动伸缩的计算密集型应用程序

 

枚举:

 从jdk 5.0开始枚举 被添加到java语言中, 不同的是,java的枚举是用类实现的。所以可以具有构造函数,方法及实例变量,甚至实现接口。

enum Apple{

	//枚举常量 被隐式声明为Apple的 public static final 成员,其类型声明为枚举的类型。

	Jonathan,GoldenDel,RedDel,Winesap,Cortland

}

public class EnumDemo {

	Apple ap = Apple.Cortland;

	

	// 比较相等性用 ==

	boolean test(Apple a){

		// 会显示名称 Jonathan

		System.out.println(a);

		

		return a == ap;

	}

	

	void switchTest(){		

		switch(ap){

		case Jonathan:

			// ...

		case GoldenDel:

			// ...

			

		default:

			// ...

		}

	}

}

 所有枚举自动包含两个预定义方法 values() 和 valueOf()

enum Apple{

	//枚举常量 被隐式声明为Apple的 public static final 成员,其类型声明为枚举的类型。

	Jonathan,GoldenDel,RedDel,Winesap,Cortland

}

public class EnumDemo {

	public static void main(String args[]){

		Apple ap;

		

		System.out.println("Here are all Apple constants");

		

		Apple allApples[] = Apple.values();

		for(Apple a : allApples){

			System.out.println(a);

		}

		

		ap = Apple.valueOf("GoldenDel");

		System.out.println("ap contains " + ap);

	}

}

 

// java枚举的类特性

enum Apple{

	// 实例对象

	Jonathan(10),GoldenDel(9),RedDel,Winesap(15),Cortland(8);

	

	// 变量

	private int price;

	

	// 构造函数

	Apple(int p){

		price = p;

	}

	

	Apple(){

		price = -1;

	}

	// 方法

	int getPrice(){

		return price;

	}

}



class EnumDemo{

	public static void main(String args[]){

		Apple ap =  Apple.Winesap;

		System.out.println("Winesap costs "+ ap.getPrice() + " cents.\n");

		

		System.out.println("All apple prices");

		for (Apple a : Apple.values()){

			

			if (a.compareTo(ap) < 0){

				System.out.println(a.ordinal() +" : " +a+" costs "+ a.getPrice()+ " cents."+ a + " before "+ ap);

			}

			else if (a.compareTo(ap) > 0){

				System.out.println(a.ordinal() +" : " +a+" costs "+ a.getPrice()+ " cents."+ a + " after "+ ap);

			}

			else {

				System.out.println(a.ordinal() +" : " +a+" costs "+ a.getPrice()+ " cents."+ a + " equal "+ ap);

			}

		}

	}

}

 

 枚举不能继承其他类,因为所有枚举都自动继承超类 java.lang.Enum, 虽然同样具有面向对象的特性,但java的枚举与swift差别很大。

 ordinal() 可以获取枚举常量在常量列表里的位置的值(序数值 0,1,2 ...)

 compareTo 可以比较相同类型的两个枚举常量的序数值。

 equals() 方法 等同 ==

 

注解(元数据) :

从jdk5 开始,java支持在源文件中嵌入补充信息,称为注释(annotation)。注释不会改变程序的动作,也就不会改变程序的语义。但在开发和部署期间,各种工具可以使用这类信息。元数据(metadata)也用于表示这一特性。

设计注释的主要目的是用于其他的开发和部署工具,但是如果为注释指定为RUNTIME保留策略,那么任何程序在运行时都可以使用反射来查询注释。反射时能够在运行时获取类相关信息的特性(java.lang.reflect)。 

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.reflect.Method;



//@interface声明一个注解类型,注解类型内部有方法声明,不能使用extends子句

//所有注解类型都自动扩展了Annotation接口(java.lang.annotation,其中重写了hashCode(),equals(),toString()

//还指定了annotationType()方法)



//保留策略:SOURCE/*只在源文件保留,编译时会被抛弃*/

//      CLASS /*在编译时存储到.class文件,但运行时通过JVM不能得到这些注释*/

//      RUNTIME /*在编译时存储到.class文件,并且运行时可以通过JVM获取这些注释*/

@Retention(RetentionPolicy.RUNTIME)

@interface MyAnno{

	 String str();

	 int val();

}



class Meta {

	

	// 应用注释时,需要为注释的成员提供值。注释的成员看起来像域变量

	@MyAnno(str = "Annotation Example",val = 100)

	public static void myMeth(String str,int i){

		Meta ob = new Meta();

		

		try{

			// 获取Class对象,之后可以获取与类声明中各个条目相关的信息,包括注释

			Class<?> c = ob.getClass(); 

			// getMethod,getField,getConstructor

			Method m = c.getMethod("myMeth",String.class,int.class);

			

			// 对Class,Method,Field,Constructor对象调用getAnnotation,可以获得与对象关联的特定注释。

			// 如果没有注释或保留策略不是RUNTIME,则返回null

			// MyAnno.class称为 类字面值,当需要已知类的Class对象时,可以用这个表达式:Class<?> c = Meta.class; 

			MyAnno anno = m.getAnnotation(MyAnno.class);

			

			System.out.println(anno.str() + " : "+ anno.val());

		}

		catch(NoSuchMethodException e){

			System.out.println("NoSuchMethodException");

		}

	}

	

	public static void main(String args[]){

		myMeth("test",10);

	}

}

 

import java.lang.annotation.Annotation;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.reflect.Method;







@Retention(RetentionPolicy.RUNTIME)

@interface MyAnno{

	String str();

	int val();

}



@Retention(RetentionPolicy.RUNTIME)

@interface What{

       // 默认值

	String description() default "Testing";

}



@What(description = "An annotation test class")

@MyAnno(str = "Meta2", val = 99)

class Meta2 {

	

	@What(description = "An annotation test method")

	@MyAnno(str = "Testing", val = 100)

	public static void myMeth(){

		Meta2 ob = new Meta2();

		try{

			// 获取Class对象,之后可以获取与类声明中各个条目相关的信息,包括注释

			Annotation[] annos =  ob.getClass().getAnnotations();

			

			System.out.println("All annotations for Meta2");

			for (Annotation a:annos){

				System.out.println(a);

			}

			

			System.out.println();

			

			Method m = ob.getClass().getMethod("myMeth");

			annos = m.getAnnotations();

			System.out.println("All annotations for myMeth");

			for (Annotation a:annos){

				System.out.println(a);

			}

		}

		catch(NoSuchMethodException e){

			System.out.println("NoSuchMethodException");

		}

	}

	

	public static void main(String args[]){

		myMeth();

	}

}

单成员注解或其他成员有默认值时,可以使用缩写形式(成员名称必须为value),

@Rentetion(RentetionPolicy.RUNTIME)

@interface MySingle{

     int value();

     int xyz() default 0;

}



class Single{

    @MySingle(88)

     public static void myMeth(){

     } 

}

  getAnnotation(),getAnnotations()由AnnotatedElement接口(java.lang.reflect)定义,

     该接口支持注解反射,类Method,Field,Constructor,Class,Package都实现了这个接口。

  getDeclaredAnnotations() 返回调用对象中存在的所有非继承注解

  isAnnotationPresent(Class<? extends Annotation> annoType) annoType指定的注解与调用对象是否相关联

  jdk 8新增:getDeclaredAnnotation() ,getAnnotationsByType()和getDeclaredAnnotationsByType(),后两个方法自动使用重复注释。

 

标记注解:

 标记注解是特殊类型的注解,其中不包含成员,唯一目的是标记声明,

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.reflect.Method;





@Retention(RetentionPolicy.RUNTIME)

@interface MyMarker{}



class Marker {

	@MyMarker

	public static void myMeth(){

		Marker ob =new Marker();

		try {

			Method	m = ob.getClass().getMethod("myMeth");

			if (m.isAnnotationPresent(MyMarker.class)){

				System.out.println("MyMarker is present");

			}

		} 

		catch (NoSuchMethodException | SecurityException e) {

			// TODO Auto-generated catch block

			e.printStackTrace();

		}

	}

	

	public static void main(String args[]){

		myMeth();

	}

}

 内置注解:

  java提供了许多内置注解,大部分为专有注解,

    但有9个用于一般目的。

    4个来自 java.lang.annotation, 只能注解其他注解

   @Retention /*指定保留策略*/,

   @Documented /*标记注解,用于通知某个工具——注解将被文档化*/,

   @Target /*用于指定可以应用注解的声明的类型*/,

  @Target(ElementType.FIELD),



  @Target({ElementType.FIELD,ElementType.LOCAL_VARIABLE})

   @Inherited /*标记注解,只影响用于类声明的注解,会导致超类的注解被子类继承。*/

   5个来自java.lang:

    @Override  /*标记注解,只能用于方法,带有此注解的方法必须重写超类中的方法,否则会编译报错。用于确保超类方法呗真正地重写,而不是简单地重载。*/

    @Deprecated/*标记注解,用于指示声明是过时的,并且已经被更新的形式取代*/

    @FunctionalInterface/*标记注解,jdk 8 新增,用于接口指出被注释的接口是一个函数式接口*/

    @SafeVarargs /*标记注解,只能用于方法和构造函数,指示没有发生与可变长度参数相关的不安全操作。用于移植“未检查不安全代码”警告。只能用于varargs方法或者 声明为static或final的构造函数*/

    @SuppressWarnings/*用于指定能抑制一个或多个编译器可能会报告的警告,使用字符串形式表示的名称来制定要被抑制的警告*/

 

类型注解

从 jdk 8开始,java增加了可以使用注解的地方,如前面的例子,早期的注解只能用于声明。但丛jdk 8开始在能够使用类型的大部分地方,也可以指定注解。扩展后的这种注解 称为 类型注解。

   类型注解 可以注解 方法的返回类型,方法内this的类型,强制转换,数组级别,被继承的类及throws子句,泛型。

   类型注解很重要,因为它们允许工具对代码执行额外的检查。

   类型注解必须包含ElementType.TYPE_USE作为目标。

   jdk 8 新增 TYPE_PARAMETER, ElementType.TYPE_USE

import java.lang.annotation.*;

import java.lang.reflect.*;



// 类型注解

@Target(ElementType.TYPE_USE)

@interface TypeAnno{}



// 类型注解

@Target(ElementType.TYPE_USE)

@interface NotZeroLen{}



// 类型注解

@Target(ElementType.TYPE_USE)

@interface Unique{}



// 类型注解

@Target(ElementType.TYPE_USE)

@interface MaxLen{

	int value();

}



// 非类型注解,用于注解泛型参数声明

@Target(ElementType.TYPE_PARAMETER)

@interface What{

	String description();

}



// 标记注解

@Target(ElementType.FIELD)

@interface EmptyOK{}



// 标记注解

@Target(ElementType.METHOD)

@interface Recommended{}



public class TypeAnnoDemo<@What(description = "Generic data type") T> {

	// 用于构造函数的类型注解

	public @Unique  TypeAnnoDemo(){}	

	// 类型注解 用于注解类型,而不是字段

	@TypeAnno String str;

	// 注解字段 test

	@EmptyOK String test;

	

	// 注解 this(接收方),this是所有实例方法的隐式参数,它引用的是调用对象。

	// 丛jdk 8开始,可以显式地将this声明为方法的第一个参数,在这种声明里,this的类型必须是其类的类型

	public int f(@TypeAnno TypeAnnoDemo<T> this,int x){

		return 10;

	}

	

	// 注解返回类型

	public @TypeAnno Integer f2(int j,int k){

		// 自动封装

		return j + k;

	}

	

	// 注释 方法声明

	public @Recommended Integer f3(String str){

		return str.length();

	}

	

	// 注解 throws 子句

	public void f4() throws @TypeAnno NullPointerException{

		// ...

	}

	

	// 注解数组级别

	String @MaxLen(10) [] @NotZeroLen [] w;

	

	// 注解数组元素类型

	@TypeAnno Integer[] vec;

	

	// 注释 extends 子句

	class SomeClass extends @TypeAnno TypeAnnoDemo<Boolean>{}

	

	public static void myMeth(int i){

		// 注解类型参数

		TypeAnnoDemo<@TypeAnno Integer> ob = 

				new TypeAnnoDemo<@TypeAnno Integer>();

		// 注解 

		@Unique TypeAnnoDemo<Integer> ob2 = new @Unique TypeAnnoDemo<Integer>();

		

		

		Object x = new Integer(10);

		Integer y;

		// 注解 类型转换

		y = (@TypeAnno Integer) x;

	}

	

	public static void main(String args[]){

		myMeth(10);

	}

}

 重复注释 :jdk 8 新增的另一个注解特性 是允许在相同元素上重复应用注释。

可重复的注释 必须用@Repeatable 进行注解。

import java.lang.annotation.*;

import java.lang.reflect.*;



@Retention(RetentionPolicy.RUNTIME)

// 指定重复注解的容器类型

@Repeatable(MyRepeatedAnnos.class)

@interface MyAnno{

	String str() default "Testing";

	int val() default 9000;

}



// 容器

@Retention(RetentionPolicy.RUNTIME)

@interface MyRepeatedAnnos{

	// value是重复注解类型的数组

	MyAnno[] value();

}



public class RepeatAnno {

	

	@MyAnno(str = "First annotation", val = -1)

	@MyAnno(str = "Second annotation", val = 100)

	public static void myMeth(String str,int i){

		RepeatAnno ob = new RepeatAnno();

		

		Class<?> c = ob.getClass();

		try {

			Method m = c.getMethod("myMeth", String.class,int.class);

			

			// 使用getAnnotation

			Annotation anno = m.getAnnotation(MyRepeatedAnnos.class);

			System.out.println(anno);

			

			// 使用jdk 8 新增的方法

			Annotation[] annos = m.getAnnotationsByType(MyAnno.class);

			for(Annotation a : annos){

				System.out.println(a);

			}

		} 

		catch (NoSuchMethodException | SecurityException e) {

			// TODO Auto-generated catch block

			e.printStackTrace();

		}

	}

	

	public static void main(String args[]){

		myMeth("test",100);

	}

}

 注解的限制:

  一个注解不能继承另一个注解。

  注解声明的方法都不带参数。

  注解不能泛型化。

  注解方法不能指定throws子句。

 

类型注解被用来支持在Java的程序中做强类型检查。配合插件式的check framework,可以在编译的时候检测出runtime error,以提高代码质量。

check framework是第三方工具,配合Java的类型注解效果就是1+1>2。它可以嵌入到javac编译器里面,可以配合ant和maven使用,也可以作为eclipse插件。地址是http://types.cs.washington.edu/checker-framework/。
check framework可以找到类型注解出现的地方并检查,举个简单的例子:

import checkers.nullness.quals.*;

public class GetStarted {

void sample() {

@NonNull Object ref = new Object();

}

}

使用javac编译上面的类

javac -processor checkers.nullness.NullnessChecker GetStarted.java

编译是通过,但如果修改成:

@NonNull Object ref = null;

如果你不想使用类型注解检测出来错误,则不需要processor,直接javac GetStarted.java是可以编译通过的,这是在java 8 with Type Annotation Support版本里面可以,但java 5,6,7版本都不行,因为javac编译器不知道@NonNull是什么东西,但check framework 有个向下兼容的解决方案,就是将类型注解nonnull用/**/注释起来
,比如上面例子修改为:

import checkers.nullness.quals.*;

public class GetStarted {

void sample() {

/*@NonNull*/ Object ref = null;

}

}

这样javac编译器就会忽略掉注释块,但用check framework里面的javac编译器同样能够检测出nonnull错误。
通过类型注解+check framework我们可以看到,现在runtime error可以在编译时候就能找到。

Java 8的类型注解:工具和机会(转)

深入理解Java:注解(Annotation)--注解处理器

  

I/O :

  通过流执行 I/O,流是一种抽象,流通过java的I/O系统链接到物理设备。所有流的行为方式都是相同的。可以将不同的输入设备(磁盘文件,键盘,网络socket抽象为输入流),对应的输出流可以引用控制台,磁盘文件,网络连接。  

   在java.io中定义了基于流的i/o,在java.nio中还定义了基于缓冲和基于通道的i/o

   java定义了两种流:字节流(在最底层,所有i/o仍然是面向字节的)和字符流(使用unicode编码,便于处理字符)

    

泛型 :

  jdk 5引入了泛型,泛型可以只定义算法一次,使其独立于特定的数据类型,然后将算法应用于各种数据类型而不需要任何额外的工作。

  泛型为语言增加的强大功能从根本上改变了代码的编写方式。

  泛型本质上是提供类型的"类型参数",它们也被称为参数化类型(parameterized type)或参量多态(parametric polymorphism)。

  在引入泛型特性之前,java是通过Object类型的引用变量来操作各种类型的对象,但它们不能以类型安全的方式进行工作。因为需要显式地使用强制类型转换

// .....

package N;



public interface Iterator{

	public Object next (); 

	public boolean hasNext (); 

}





// .....

package N;



public interface Collection{

	public void add(Object x);

	public Iterator iterator();

}





// .....

package N;



public class NoSuchElementException extends RuntimeException {

	

}





// .....

package N;



public class MyLinkedList implements Collection {

	protected class Node{

		Object elt;

		Node next = null; 

		

		Node (Object elt) { this.elt = elt; } 

	}



	protected Node head = null, tail = null; 

	

	public MyLinkedList () {} 

	

	@Override

	public void add(Object elt) {

		// TODO Auto-generated method stub

		if (head == null) { head = new Node(elt); tail = head; } 

		else { tail.next = new Node(elt); tail = tail.next; } 

	}



	@Override

	public Iterator iterator() {

		// TODO Auto-generated method stub

		return new Iterator () { 

			 protected Node ptr = head; 

			 public boolean hasNext () { 

				 return ptr != null; 

			 }

			 public Object next () { 

				 if (ptr != null) { 

					 Object elt = ptr.elt; 

					 ptr = ptr.next; 

					 return elt;

				 } 

				 else {

					 throw new NoSuchElementException (); 

				 }

			 } 

		};

	}

}





// .....

import N.*;



public class Test {



	public static void main(String[] args) {

		MyLinkedList xs = new MyLinkedList(); 

		xs.add(new Byte((byte) 0));

		xs.add(new Byte((byte) 1)); 

		Iterator xi = xs.iterator();

		while(xi.hasNext()){

			Byte x = (Byte)xi.next(); 

			System.out.println("Byte:"+ x);

		}

		

		System.out.println();

		MyLinkedList ys = new MyLinkedList();

		ys.add("zero");

		ys.add("one"); 

		Iterator yi = ys.iterator();

		while(yi.hasNext()){

			String y = (String) yi.next();

			System.out.println("String:"+ y);

		}



		System.out.println();

		MyLinkedList zs = new MyLinkedList();

		zs.add(ys);

		zs.add(ys);

		Iterator zi = zs.iterator();

		while(zi.hasNext()){

			MyLinkedList zlist = (MyLinkedList)zi.next();

			Iterator zzi = zlist.iterator();

			while(zzi.hasNext()){

				String y = (String) zzi.next();

				System.out.println("String:"+ y);

			}

		}

		

		Byte w = (Byte)ys.iterator().next(); // run-time exception

		System.out.println("Byte:"+ w);

	}

}

 上面的例子,编译器不知道Object的实际类型,无法发现强制类型转换的错误,需要到运行时才会抛出。这一缺陷推迟了发现错误的时间。使用泛型实现,则可以在编译时就发现错误。

package T;



public interface Collection<T> {

	 public void add(T x); 

	 public Iterator<T> iterator(); 

}





// ...

package T;



public interface Iterator<T> {

	 public T next(); 

	 public boolean hasNext(); 

}





// ...

package T;



import N.NoSuchElementException;



public class MyLinkedList<T> implements Collection<T> {

	protected class Node{

		Node next = null;

		T elt;

		

		Node(T elt){

			this.elt =elt;

		}

	}

	

	protected Node head = null,tail = null;

	public MyLinkedList () {}

	

	@Override

	public void add(T x) {

		// TODO Auto-generated method stub

		if(head == null){

			head = new Node(x);

			tail = head;

		}

		else{

			tail.next = new Node(x);

			tail = tail.next;

		}

	}

	@Override

	public Iterator<T> iterator() {

		// TODO Auto-generated method stub

		return new Iterator<T> (){

			protected Node ptr = head;

			

			@Override

			public T next() {

				// TODO Auto-generated method stub

				if (ptr != null) { 

					 T elt = ptr.elt; 

					 ptr = ptr.next; 

					 return elt;

				 } 

				 else {

					 throw new NoSuchElementException (); 

				 }

			}



			@Override

			public boolean hasNext() {

				// TODO Auto-generated method stub

				return ptr != null;

			}

		};

	} 

}





// ...

import T.*;



public class Test {



	public static void main(String[] args) {

		MyLinkedList<Byte> xs = new MyLinkedList<Byte>(); 

		xs.add(new Byte((byte) 0));

		xs.add(new Byte((byte) 1)); 

		Iterator<Byte> xi = xs.iterator();

		while(xi.hasNext()){

			Byte x = xi.next(); 

			System.out.println("Byte:"+ x);

		}

		

		System.out.println();

		MyLinkedList<String> ys = new MyLinkedList<String>();

		ys.add("zero");

		ys.add("one"); 

		Iterator<String> yi = ys.iterator();

		while(yi.hasNext()){

			String y = yi.next();

			System.out.println("String:"+ y);

		}



		System.out.println();

		MyLinkedList<MyLinkedList<String>> zs = new MyLinkedList<MyLinkedList<String>>();

		zs.add(ys);

		zs.add(ys);

		Iterator<MyLinkedList<String>> zi = zs.iterator();

		while(zi.hasNext()){

			MyLinkedList<String> zlist = zi.next();

			Iterator<String> zzi = zlist.iterator();

			while(zzi.hasNext()){

				String y = zzi.next();

				System.out.println("String:"+ y);

			}

		}

	}

}

String 是 Object 的子类型,因此,我们可以将 String 类型的变量赋值给 Object 类型的变量,甚至可以将 String [ ] 类型的变量(数组)赋值给 Object [ ] 类型的变量,即 String [ ] 是 Object [ ] 的子类型。 但这一特性不适用于泛型。

 List<String> ls = new ArrayList<String>(); 

 List<Object> lo = ls; // 报错,破坏了泛型 的类型安全

lo.add(new Integer()); 

String s = ls.get(0);

 受限的类型参数(有界类型)

// 在指定参数类型时,可以声明超类的上界,默认上界是Object

// 要调用doubleValue(),需要声明 类型参数T必须派生自Number

// 当需要指定具有一个类和多个接口的边界时,使用 & 运算符连接 它们

// class Gen(T extends MyClass & MyInterface & MyInterface2 {}

public class Stats<T extends Number> {

	T[] nums;

	

	Stats(T[] o){

		nums = o;

	}

	

	double average(){

		double sum = 0.0;

		for(int i =0;i<nums.length;i++){

			sum += nums[i].doubleValue();

		}

		return sum / nums.length;

	}

	

	boolean sameAvg(Stats<T> ob){

		if(average() == ob.average()){

			return true;

		}

		return false;

	}

}

通配符参数 :

  上例的sameAvg()只有比较双方的类型相同时才能工作,不能比对 Stats<Double>与Stats<Integer>

// 使用通配符参数 ?

boolean sameAvg(Stats<?> ob){

	if(average() == ob.average()){

		return true;

	}

	return false;

}

 上例通配符只是简单地匹配所有有效的Stats对象,范围由Stats声明中的extends子句控制。

  而如同有界参数一样,通配符也可以增加限制,不同在于有界通配符不仅可以有上界<? extends superclass>,也可以有下界<? super subclass>

class TwoD{

	int x,y;

	TwoD(int a,int b){

		x = a;

		y =b;

	}

}

class ThreeD extends TwoD{

	int z;

	ThreeD(int a,int b, int c){

		super(a, b);

		z = c;

	}

}

class FourD extends ThreeD{

	int t;

	FourD(int a, int b, int c,int d) {

		super(a, b, c);

		t = d;

	}

}



class Coords<T extends TwoD>{

	T[] coords;

	Coords(T[] o){

		coords = o;

	}

}



public class BoundedWildcards {

	static void showXY(Coords<?> c){

		System.out.println("X Y Coordinates:");

		for (int i = 0; i < c.coords.length; i++) {

			System.out.println(c.coords[i].x + " " + c.coords[i].y);

		}

		System.out.println();

	}

	

	static void showXYZ(Coords<? extends ThreeD> c){

		System.out.println("X Y Z Coordinates:");

		for (int i = 0; i < c.coords.length; i++) {

			System.out.println(c.coords[i].x + " " + c.coords[i].y+ " " + c.coords[i].z);

		}

		System.out.println();

	}

	

	static void showAll(Coords<? extends FourD> c){

		System.out.println("X Y Z T Coordinates:");

		for (int i = 0; i < c.coords.length; i++) {

			System.out.println(c.coords[i].x + " " + c.coords[i].y+ " " + c.coords[i].z+ " " + c.coords[i].t);

		}

		System.out.println();

	}

	

	public static void main(String[] args) {

		TwoD td[] = {

				new TwoD(0, 0),

				new TwoD(7, 9),

				new TwoD(18, 4),

				new TwoD(-1, -23),

				new TwoD(22, 44)

		};

		Coords<TwoD> tdlos = new Coords<>(td);

		System.out.println("Contens of tdlos:");

		showXY(tdlos);

		// 编译报错

		//showXYZ(tdlos);

		//showAll(tdlos);

		

		FourD fd[] = {

				new FourD(1, 2, 3, 4),

				new FourD(6, 8, 9, 14),

				new FourD(22, 9, 23, 4),

				new FourD(3, -2, 53, -4),

		};

		

		Coords<FourD> fdlos = new Coords<>(fd);

		System.out.println("Contens of fdlos:");

		showXY(fdlos);

		showXYZ(fdlos);

		showAll(fdlos);

	}

}

public interface Stream<T> extends BaseStream<T, Stream<T>> {



    Stream<T> filter(Predicate<? super T> predicate);



    <R> Stream<R> map(Function<? super T, ? extends R> mapper);



    IntStream mapToInt(ToIntFunction<? super T> mapper);



    LongStream mapToLong(ToLongFunction<? super T> mapper);



    DoubleStream mapToDouble(ToDoubleFunction<? super T> mapper);



    <R> Stream<R> flatMap(Function<? super T, ? extends Stream<? extends R>> mapper);

    // ...

}

  

 前面的是泛型类,泛型参数

泛型方法的格式 public <T extends Comparable<T>, V extends T> boolean isIn(T x, V[] y){}

public class GenMethDemo {

	

	static <T extends Comparable<T>,V extends T> boolean isIn(T x, V[] y){

		for (int i = 0; i < y.length; i++) {

			if(x.equals(y[i])){

				return true;

			}

		}

		return false;

	}

	

	public static void main(String[] args) {

		Integer nums[] ={

				1,2,3,4,5

		};

		

		// 完整形式 GenMethDemo.<Integer,Integer>isIn(2,nums),但对大多数泛型方法,类型推断就足够了

		if(isIn(2,nums)){

			System.out.println("2 is in nums");

		}

		

		System.out.println();

		

		String strs[] ={

				"one","two","three","four","five"

		};

		

		if(isIn("two",strs)){

			System.out.println("two is in strs");

		}

	}

}

 泛型构造函数; 可以将构造函数泛型化,即使它们的类不是泛型类

class GenericConstructor {

	private double val;

	

	<T extends Number> GenericConstructor(T arg){

		val = arg.doubleValue();

	}

	

	void showVal(){

		System.out.println("val: "+ val);

	}

}



class GenConDemo{

	public static void main(String[] args) {

		GenericConstructor test1 = new GenericConstructor(100);

		GenericConstructor test2 = new GenericConstructor(123.5F);

		

		test1.showVal();

		test2.showVal();

	}

}

 泛型接口:使用接口作为泛型的上界时,也用extends, 具体形式与泛型类相同

package T;



public interface Comparable<T> {

	int compareTo(T that);

}





// ...

package T;



public class MyByte implements Comparable<MyByte> {

	private byte value; 

	public MyByte(byte value) {this.value = value;} 

	public byte byteValue() {return value;} 

	@Override

	public int compareTo(MyByte that) {

		return this.value - that.value; 

	}

	public String toString(){

		return "" + value;

	}

}





// ...

package T;



public class Collections {

  public static <A extends Comparable<A>> A max (Collection<A> xs){

		Iterator<A> xi = xs.iterator(); 

		A w = xi.next(); 

		while (xi.hasNext()) { 

		 	A x = xi.next(); 

			if (w.compareTo(x) < 0) w = x; 

		} 

		return w;

	}

}





// ...

import T.*;



public class Test {



	public static void main(String[] args) {

		MyLinkedList<MyByte> xxs = new MyLinkedList<MyByte>(); 

		xxs.add(new MyByte((byte) 3));

		xxs.add(new MyByte((byte) 4)); 

		Iterator<MyByte> xxi = xxs.iterator();

		while(xxi.hasNext()){

			MyByte x = xxi.next(); 

			System.out.println("MyByte:"+ x);

		}

		

		MyByte xx = Collections.max(xxs);

		System.out.println("max MyByte:"+ xx);

                System.out.println("type of xx is: "+ xx.getClass().getName());

	}

}

 

// public interface Comparable<T> {}

interface MinMax<T extends Comparable<T>>{

	T min();

	T max();

}



class MyClass<T extends Comparable<T>> implements MinMax<T>{

	T[] vals;

	MyClass(T[] o){

		vals = o;

	}

	@Override

	public T min() {

		if (vals.length == 0)return null;

		T v = vals[0];

		for (int i = 0; i < vals.length; i++) {

			if(vals[i].compareTo(v)< 0) {

				v= vals[i];

			}

		}

		return v;		

	}



	@Override

	public T max() {

		if (vals.length == 0)return null;

		T v = vals[0];

		for (int i = 0; i < vals.length; i++) {

			if(vals[i].compareTo(v)> 0) {

				v= vals[i];

			}

		}

		return v;	

	}	

}



public class GenericInterface {

	public static void main(String[] args) {

		Integer inums[]={

				3,6,2,8,6

		};

		Character chs[] ={

			'b','r','p','w'	

		};

		

		MyClass<Integer> iob = new MyClass<>(inums);

		MyClass<Character> cob = new MyClass<>(chs);

		

		System.out.println("Max value in inums is :" + iob.max());

		System.out.println("Min value in inums is :" + iob.min());

		

		System.out.println("Max value in chs is :" + cob.max());

		System.out.println("Min value in chs is :" + cob.min());

	}

}

 

因为java的泛型只支持引用类型,不支持基本数据类型。所以jdk 5提供的自动装箱与自动拆箱,可以极大地简化代码,

 而从jdk 7 开始,可以进一步缩短创建泛型实例的语法。

 MyClass<Integer,String> mcOb = new  MyClass<Integer,String>(new Integer(88),"A String");

 MyClass<Integer,String> mcOb = new  MyClass<Integer,String>(88,"A String"); 

 MyClass<Integer,String> mcOb = new  MyClass<>(88,"A String");

 泛型类作为超类和子类时,在泛型层次中,所有子类都必须向上传递超累所需的所有类型参数。与沿类层次向上传递构造函数的参数类似。

 

泛型层次中的 运行时类型比较 及强制转换

class Gen<T>{

	T ob;

	Gen(T o){

		ob = o;

	}

}

class Gen2<T> extends Gen<T>{

	Gen2(T o){

		super(o);

	}

}



class GenInstanceof {

	public static void main(String[] args) {

		Gen<Integer> iOb = new Gen<>(88);

		Gen2<Integer> iOb2 = new Gen2<>(99);		

		Gen2<String> strOb2 = new Gen2<>("Generics Test");

		

		if(iOb2 instanceof Gen2<?>){

			System.out.println("iobs is instance of Gen2");

		}

		

		if(iOb2 instanceof Gen<?>){

			// 强制类型转换,因为iOb2是Gen<Integer>的实例

			Gen<Integer> iObcast = (Gen<Integer>) iOb2;

			

			System.out.println("iobs is instance of Gen");

		}

		

		if(strOb2 instanceof Gen2<?>){

			System.out.println("strOb2 is instance of Gen2");

		}

		

		if(strOb2 instanceof Gen<?>){

			System.out.println("strOb2 is instance of Gen");

		}

		

		System.out.println();

		

		if(iOb instanceof Gen2<?>){

			System.out.println("iOb is instance of Gen2");

		}

		else{

			System.out.println("iOb is not instance of Gen2");

		}

		

		if(iOb instanceof Gen<?>){

			System.out.println("iOb is instance of Gen");

		}



		//不能编译通过,因为在运行时不能使用泛型类型信息。

//		if(iOb2 instanceof Gen<Integer>){

//			System.out.println("iOb2 is instance of Gen<Integer>");

//		}

	}

}

  

  泛型 与 c++ 中的模板很类似,但二者处理泛型类型的方式有本质区别

   在 C++ 模板中,编译器使用提供的类型参数来扩充模板,类似字符替换的过程。

   而在java中,影响泛型实现方式的一个重要约束就是需要与以前的JAVA版本兼容。为此JAVA才用"擦除"实现泛型。java虚拟机是不支持泛型的,java的泛型会在编译过程中,首先转化为不带泛型的普通java程序。所以在运行时没有类型参数,它们只是一种源代码机制。转化过程中包含几个部分:

  • 将参数化类型中的类型参数"擦除"(erasure)掉
  • 将类型变量用"上限(upper bound)"取代,通常情况下这些上限是 Object。增加适当的类型转换,以保持与类型参数所指定类型的兼容性。
    /*
    
    class Gen<T>{
    
    	T ob;
    
    	Gen(T o){
    
    		ob = o;
    
    	}
    
    	T getOb(){
    
    		return ob;
    
    	}
    
    } 
    
     */
    
    class Gen{
    
    	Object ob;
    
    	Gen(Object o){
    
    		ob =o;
    
    	}
    
    	Object getOb(){
    
    		return ob;
    
    	}
    
    }
    
    /*
    
    class Gen2 extends Gen<String>{
    
    	Gen2(String o) {
    
    		super(o);
    
    	}
    
    } 
    
     */
    
    class Gen2 extends Gen{
    
    	Gen2(String o) {
    
    		super(o);
    
    	}
    
    }
    
    
    
    
    
    class GenericBridgeDemo {
    
    	public static void main(String[] args) {
    
    		/*
    
    		Gen2 strOb2 = new Gen2("Generics Test");
    
    		String ob = strOb2.getOb();
    
    		System.out.println(ob); 
    
    		 */
    
    		Gen2 strOb2 = new Gen2("Generics Test");
    
    		String ob = (String) strOb2.getOb();
    
    		System.out.println(ob);
    
    	}
    
    }
    
    

     

  • 添加类型转换并插入"桥方法"(bridge method),以便覆盖(overridden)可以正常的工作。
    /*
    
    interface Comparable<T extends Number> {
    
    	int compareTo(T that);
    
    }
    
     */
    
    interface Comparable {
    
    	int compareTo(Number that);
    
    }
    
    
    
    /*
    
    class MyByte extends Number implements Comparable<MyByte> {
    
    	private static final long serialVersionUID = 2L;
    
    	
    
    	private byte value; 
    
    	public MyByte(byte value) {this.value = value;} 
    
    	public byte byteValue() {return value;} 
    
    	public int intValue() {return value;} 
    
    	public long longValue() {return value;} 
    
    	public float floatValue() {return value;} 
    
    	public double doubleValue() {return value;} 
    
    	
    
    	public int compareTo(MyByte that) {
    
    		return this.value - that.value; 
    
    	}
    
    	public String toString(){
    
    		return "" + value;
    
    	}
    
    }
    
     */
    
    class MyByte extends Number implements Comparable {
    
    	private static final long serialVersionUID = 2L;
    
    	
    
    	private byte value; 
    
    	public MyByte(byte value) {this.value = value;} 
    
    	public byte byteValue() {return value;} 
    
    	public int intValue() {return value;} 
    
    	public long longValue() {return value;} 
    
    	public float floatValue() {return value;} 
    
    	public double doubleValue() {return value;} 
    
    	
    
    	public int compareTo(MyByte that) {
    
    		return this.value - that.value; 
    
    	}
    
    	public String toString(){
    
    		return "" + value;
    
    	}
    
    	
    
    	// 为了可以正常覆盖超类和接口的方法,引入了桥方法
    
    	public int compareTo(Number that) {
    
    		return this.compareTo((MyByte)that);
    
    	}
    
    }
    
    
    
    
    
    class GenericBridgeDemo{
    
    	public static void main(String[] args) {
    
    		MyByte a = new MyByte((byte)88);
    
    		MyByte b = new MyByte((byte)77);
    
    		MyByte c = new MyByte((byte)77);
    
    		MyByte d = new MyByte((byte)99);
    
    		
    
    		System.out.println(a.intValue());
    
    		System.out.println(a.doubleValue());
    
    		if (a.compareTo(b) > 0){
    
    			System.out.println("a > b");
    
    		}
    
    		if (a.compareTo(d) < 0){
    
    			System.out.println("a < d");
    
    		}
    
    		if (b.compareTo(c) == 0){
    
    			System.out.println("b == c");
    
    		}
    
    	}
    
    }
    
    
/*

class Gen2 extends Gen<String>{

	Gen2(String o) {

		super(o);

	}

	String getOb(){

		System.out.println("调取 gen2.getOb()");

		return ob;

	}

} 

 */

class Gen2 extends Gen{

	Gen2(String o) {

		super(o);

	}

	String getOb(){

		System.out.println("调取 gen2.getOb()");

		return (String) ob;

	}

	//在 JVM 中,方法定义时所使用的方法签名包括方法的返回类型,所以覆盖需要一个桥方法

	Object getOb(){

		return this.getOb();

	}

}

 

java泛型的优点:

  • 类型安全。 泛型的一个主要目标就是提高 Java 程序的类型安全。使用泛型可以使编译器知道变量的类型限制,进而可以在更高程度上验证类型假设。如果没有泛型,那么类型的安全性主要由程序员来把握,这显然不如带有泛型的程序安全性高。
  • 消除强制类型转换。泛型可以消除源代码中的许多强制类型转换,这样可以使代码更加可读,并减少出错的机会。
  • 向后兼容。支持泛型的 Java 编译器(例如 JDK5.0 中的 Javac)可以用来编译经过泛型扩充的 Java 程序(GJ 程序),但是现有的没有使用泛型扩充的 Java 程序仍然可以用这些编译器来编译。
  • 层次清晰,恪守规范。无论被编译的源程序是否使用泛型扩充,编译生成的字节码均可被虚拟机接受并执行。也就是说不管编译器的输入是 GJ 程序,还是一般的 Java 程序,经过编译后的字节码都严格遵循《 Java 虚拟机规范》中对字节码的要求。可见,泛型主要是在编译器层面实现的,它对于 Java 虚拟机是透明的。
  • 性能收益。目前来讲,用 GJ 编写的代码和一般的 Java 代码在效率上是非常接近的。 但是由于泛型会给 Java 编译器和虚拟机带来更多的类型信息,因此利用这些信息对 Java 程序做进一步优化将成为可能。
区别: 
  • Java 语言中的泛型不能接受基本类型作为类型参数――它只能接受引用类型。这意味着可以定义 List<Integer>,但是不可以定义 List<int>。
  • 在 C++ 模板中,编译器使用提供的类型参数来扩充模板,因此,为 List<A> 生成的 C++ 代码不同于为 List<B> 生成的代码,List<A> 和 List<B> 实际上是两个不同的类。
    // 这个可以编译。不过使用这个函数的时候,T必须是包含bar函数的类
    
    template <typename T>
    
    void foo(T t) {
    
     t.bar();
    
    }
    
    
    
    // java 则不行,因为编译器只知道T是一种Object,不知道T的具体类型
    
    static <T> void foo(T t) {
    
      t.bar();
    
    }
  • 而 Java 中的泛型则以不同的方式实现,编译器仅仅对这些类型参数进行擦除和替换。类型 ArrayList<Integer> 和 ArrayList<String> 的对象共享相同的类,并且只存在一个 ArrayList 类。因此在c++中存在为每个模板的实例化产生不同的类型,这一现象被称为“模板代码膨胀”,而java则不存在这个问题的困扰。java中虚拟机中没有泛型,只有基本类型和类类型,泛型会被擦除,一般会修改为Object,如果有限制,例如 T extends Comparable,则会被修改为Comparable。而在C++中不能对模板参数的类型加以限制,如果程序员用一个不适当的类型实例化一个模板,将会在模板代码中报告一个错误信息。

 模糊性错误

class MyGenClass<T,V extends Number>{

	T ob1;

	V ob2;

	

	MyGenClass(T o1,V o2){

		ob1 = o1;

		ob2 = o2;

	}

	

	void set(T o){

		ob1 = o;

	}

	

	// 通过编译但存在模糊性错误,这里最好使用不同的方法名

	void set(V o){

		ob2 = o;

	}

	public String toString(){

		return ob1+","+ ob2;

	}

}

public class GenericsError {

	public static void main(String[] args) {

		MyGenClass<Integer,Integer> iob = new MyGenClass<>(1,2);

		iob.set(12);

		System.out.println(iob);

	}

}

 

 限制:

1. 不能创建类型 为参数类型 的实例方法  ob = new T(); T vals[] = new T[10];

2. 静态成员不能使用在类中声明的类型参数 static T ob;  Static T getOb();

 

3. 不能创建特定类型的泛型引用数组

     Gen<Integer> gens[] = new Gen<Integer>[10]; // wrong

     Gen<?> gens[] = new Gen<?>[10] //ok

4.  同上 运行时比较:

    if( iob instanceof Gen<Integer>){} // wrong

    if(iob instanceof Gen<?>){}

5. 泛型不能扩展Throwable,即不能创建泛型异常类

lambda表达式 :

  java发展过程中从根本上改变代码编写方式的两次变更:jdk 5增加的泛型 和 jdk 8增加的 lambda表达式

 lambda显著增强java,原因有两点:

1. 它增加了语法元素,使java的表达能力得以提升,并流线化了一些常用结构的实现方式。

2. 导致api库中增加了新功能,包括利用多核环境的并行处理功能(尤其是处理for-each风格的操作时)变得更加容易。以及支持对数据执行管道操作的新的流api。也催生了其他新的java功能,包括方法引用和接口的默认方法。

 ------------------------------------------------------

lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包

 闭包是一个代码块,一个函数,它可以捕获其上下文中任意的变量和常量,延长其的生存周期以供自己使用,把函数以及这些变量包起来,而可以独立完成一个完整的功能。同时它如同普通数据类型的数据一样可以做参数,可以做返回值,参与了其他代码模块的构建。

——————

java的匿名内部类(没有类名,实例化后立即执行,只有一个实例,也不可被扩展,而且使用内联的方式使代码出现在使用它的位置。) 基本实现了闭包的功能,一直被称作JAVA的闭包。

匿名内部类的 捕获策略: 局部变量 必须是final,原因:

用函数实现闭包,需要提高函数的地位,JAVA坚持了它的面向对象的纯粹性,依然是只有class 为 first class, 使用简单类代替函数。

用函数实现,捕获的变量会加入参数列表,而函数的参数可以传递指针。类中变量的传入则是依靠构造函数,在匿名类内部建立同名的field,而为了保持内外的一致性,只好全部声明为final。

所以匿名内部类实现的闭包,使用起来似乎没有C#,SWIFT那样灵活了,不过考虑到java中基本全是类实现,所以这一限制其实也不算什么问题,不便的是基本数据类型,如果要使用的话,需要借助数组等形式,封装器值的变更实际是在构造新的实例,所以不适用。

但同时它传递的是一个类,不像函数式闭包只能传一个函数,它可以传任意个。虽然可能牺牲了可读性,但在匿名内部类中不光可以实现接口中定义的任意个方法,甚至可以自行添加字段,方法等元素。

import java.util.ArrayList;

import java.util.List;



public class Nest {

	List<Runnable> getList2(int n){

		List<Runnable> actions = new ArrayList<Runnable>();

		final int x[] = new int[1];

		x[0] = 0;

		for (; x[0] < n; x[0]++)

	       {

	             actions.add(

	        		new Runnable(){

	        			public void run()

	    	                       {

	    	                             System.out.println(x[0]);

	    	                       }

	        		}

	        );

	    }

		return actions;

	}

	List<Runnable> getList(int n){

		List<Runnable> actions = new ArrayList<Runnable>();

		for (int counter=0; counter < n; counter++)

	      {

	        final int copy = counter;

	        actions.add(

	        		new Runnable(){

	        			public void run()

	    	                         {

	    	                                 System.out.println(copy);

	    	                        }

	        		}

	        );

	        // Local variable copy defined in an enclosing scope must be final or effectively final

	        // copy = 10;

	    }

		return actions;

	}

	public static void main(String[] args)

	{

		Nest ccc = new Nest();

		List<Runnable> actions = ccc.getList(15);

		print(actions);

		System.out.println();

		actions = ccc.getList2(15);

		print(actions);

	}

	

	static void print(List<Runnable> actions){

		for (Runnable action : actions)

	    {

	        action.run();

	    }

	}

}  

 实现机制

import java.util.ArrayList;

import java.util.List;



public class Nest {

	List<Runnable> getList(int n){

		List<Runnable> actions = new ArrayList<Runnable>();

		for (int counter=0; counter < n; counter++)

	    {

	        final int copy = counter;

	        class temp implements Runnable{

	        	final int copy;

	        	temp(int copy){

	        		this.copy = copy;

	        	}

	        	

	        	public void run()

	            {

	                System.out.println(copy);

	            }

	        }

	        actions.add(new temp(copy));

	    }

		return actions;

	}

	public static void main(String[] args)

	{

		Nest ccc = new Nest();

		List<Runnable> actions = ccc.getList(15);

		print(actions);

	}

	

	static void print(List<Runnable> actions){

		for (Runnable action : actions)

	    {

	        action.run();

	    }

	}

}

java的 lambda表达式 就是一个实现单一方法的匿名内部类的简化版。使用lambda表达式 代码变得简洁,可读性提高,代码量也大大减少。

// 匿名内部类

button.addActionListener(

    new ActionListener(){

        public void actionPerformed(ActionEventae){

            System.out.println("Actiondetected");

        }

    }

);

使用Lambda:

button.addActionListener(

    ()->{

    System.out.println("Actiondetected");

    }

);    

不便:

1 . 用函数实现闭包,函数自身的参数列表和返回值类型本身就自解释了自身的类型。而JAVA的lambda表达式是一个类,它无法独立存在, 需要一个函数式接口来定义一个方法(规定函数的类型),使得代码依然比函数实现要复杂。 jdk 8 同时增加了java.util.funciton包,定义了许多常用的函数式接口。

2.  局部变量只能捕获 final 修饰符修饰的变量。。

3.  类实现的闭包不易扩展,使用也需要多一步操作。 

let newBlock = ()->{

     if(some){

          block()

     }

}

 

函数式接口是仅包含一个抽象方法(有默认行为的方法不算抽象方法)的接口。即通常仅表示单个动作。此外函数式接口定义了lambda表达式的目标类型。同时Object的公有方法也是函数式接口的隐式成员。

java中的 lambda表达式 格式:

()-> 123.45   // double f(){return 123.45}

()-> Math.random()*100 // double f(){ return Math.random()*100;}

(n)->(n%2)==0 // boolean f(Int n){ return (n%2)==0} 

(n)->n*2 // 参数类型和返回类型各是什么呢?需要函数式接口的定义

可以显式指定n的类型: (int n) -> n * 2

public class Lambda {

	interface MyNumber{

		double getValue();

		default int getNum(){

			return 10;

		}

	}

	public static void main(String[] args) {

		MyNumber mynum = ()-> 123;

		System.out.println(mynum.getValue());

		System.out.println(mynum.getNum());

		System.out.println();

		final MyNumber mynum2 = ()-> Math.random() * 100 ;

		System.out.println(mynum2.getValue());

		System.out.println(mynum2.getValue());

		System.out.println();

		MyNumber mynum3 = ()->{

			int result =1;

			int n = (int)(mynum2.getValue());

			System.out.println(n);

			for(int i = 1; i<n;i++){

				result = (int)(Math.sqrt(result * i)) ;

			}

			return result;

		};

		System.out.println(mynum3.getValue());

	}

}

 

public class Lambda {

	interface MyNumber<T extends Number>{

		void getValue(T o);

	}

	public static void main(String[] args) {

		Lambda l = new Lambda();

		l.forI().getValue(12); 

		System.out.println();

		l.print().getValue(0b1001);

	}

	

	<T extends Number> MyNumber<T> print(){

		return (n)->{

			System.out.println(n);

		};

	}

	

	MyNumber<Integer> forI(){

		return (n)->{

			for (int i = 0; i < n; i++) {

				System.out.println(i);

			}

		};

	}

}

c#中的闭包:

namespace Lambda

{

    class Program

    {

        static  void Main()

        {

            Program aa = new Program();

            List<Action> actions = aa.get();

            //执行动作  

            foreach (Action action in actions)

            {

                // 是一个函数

                action();

            }

            Console.ReadKey();

        }

        List<Action> get()

        {

            //定义动作组  

            List<Action> actions = new List<Action>();

            for (int counter = 0; counter < 10; counter++)

            {

                actions.Add(() => { Console.WriteLine(counter); });

            }

            return actions;

        }

    }

}

 c#中函数可以作为返回值,作为参数,可以柯里化,但函数不能嵌套函数

namespace Lambda

{

    class Program

    {

        static  void Main()

        {

            Program aa = new Program();



            Console.WriteLine(aa.get2()(1)(2));

            Console.WriteLine(aa.calculate(1, 2, aa.get2()));

            Console.WriteLine(

                aa.get3()(

                    () =>

                    {

                        Random r = new Random();

                        return r.Next(100);

                    }

                )()

            );

            Console.ReadKey();

        }



        // 函数可以作为返回值,作为参数,可以柯里化

        Func<int, Func<int, int>> get2()

        {

            return x => y => x + y;

        }



        int calculate(int a,int b,Func<int, Func<int, int>> f){

            return f(a)(b);

        }



        Func<Func<int>, Func<bool>> get3()

        {

            return (x) =>

            {

                return () => x() > 50;

            };

        }

    }

}

 lambda表达式可以抛出异常

interface DoubleNumericArrayFunc{

	double func(double[] n) throws EmptyArrayException;

}



class EmptyArrayException extends Exception{

	EmptyArrayException(){

		super("Array empty");

	}

}



public class LambdaException {

	public static void main(String[] args) throws EmptyArrayException {

		double values[] = {1,2,3,4};

		

		DoubleNumericArrayFunc average = (n)->{

			double sum =0;

			if(n.length == 0){

				throw new EmptyArrayException();

			}

			for (int i = 0; i < n.length; i++) {

				sum += n[i];

			}

			return sum / n.length;

		};

		

		System.out.println("The avarage is : "+ average.func(values));

		System.out.println("The avarage is : "+ average.func(new double[0]));

	}

}

方法引用:

interface StringFunc{

	String func(String n);

}

class MyStringOps{

	static String strReverse(String str){

		String result ="";

		int i;

		for (i = str.length() - 1; i >= 0; i--) {

			result += str.charAt(i);

		}

		return result;

	}

}



class LambdaRefMethod {

	static String stringOp(StringFunc sf,String s){

		return sf.func(s);

	}

	public static void main(String[] args) {

		String inStr = "Lambda add power to java";

		String outStr;

		

		/*

		 * 可将 对 MyStringOps中声明的静态方法 strReverse 的引用 传递给 stringOp的第一个参数

		 * 因为strReverse 与 函数式接口 StringFunc 兼容(二者的函数类型一致),用strReverse提供

		 * 了StringFunc的方法实现。

		 */

		outStr = stringOp(MyStringOps::strReverse,inStr);

		System.out.println("Orginal String : " + inStr);

		System.out.println("String Reversed : " + outStr);

	}

}

 上面是静态方法的引用传递,实例方法的引用传递,用实例对象引用方法

interface StringFunc{

	String func(String n);

}

class MyStringOps{

	String strReverse(String str){

		String result ="";

		int i;

		for (i = str.length() - 1; i >= 0; i--) {

			result += str.charAt(i);

		}

		return result;

	}

}



class LambdaRefMethod {

	static String stringOp(StringFunc sf,String s){

		return sf.func(s);

	}

	public static void main(String[] args) {

		String inStr = "Lambda add power to java";

		String outStr;

		

		MyStringOps ops = new MyStringOps();

		outStr = stringOp(ops::strReverse,inStr);

		System.out.println("Orginal String : " + inStr);

		System.out.println("String Reversed : " + outStr);

	}

}

对于实例引用,也可以使用类名引用方法。 还可以 用super 引用 方法的 超类版本。  

interface MyFunc<T>{

	boolean func(T v1,T v2);

}



class HighTemp{

	private int hTemp;

	HighTemp(int ht) {

		hTemp = ht;

	}

	

	boolean sameTemp(HighTemp ht2){

		return hTemp == ht2.hTemp;

	}

	

	boolean lessThenTemp(HighTemp ht2){

		return hTemp < ht2.hTemp;

	}

}



class LambdaRefMethod{

	static <T> int counter(T[] vals,MyFunc<T> f,T v){

		int count =0;

		for (int i = 0; i < vals.length; i++) {

			if(f.func(vals[i], v)){

				count ++;

			}

		}

		return count;

	}

	

	public static void main(String[] args) {

		int count;

		

		HighTemp[] weekDayHighs ={

				new HighTemp(89),new HighTemp(82),

				new HighTemp(90),new HighTemp(89),

				new HighTemp(89),new HighTemp(91),

				new HighTemp(84),new HighTemp(83)

		};

		

		count = counter(weekDayHighs,HighTemp::sameTemp,new HighTemp(89));

		System.out.println(count + " days had a high of 89");

		

		HighTemp[] weekDayHighs2 ={

				new HighTemp(32),new HighTemp(12),

				new HighTemp(24),new HighTemp(19),

				new HighTemp(18),new HighTemp(12),

				new HighTemp(-1),new HighTemp(13)

		};

		count = counter(weekDayHighs2,HighTemp::sameTemp,new HighTemp(12));

		System.out.println(count + " days had a high of 12");

		

		count = counter(weekDayHighs,HighTemp::lessThenTemp,new HighTemp(89));

		System.out.println(count + " days had a high less than 89");

		

		count = counter(weekDayHighs2,HighTemp::lessThenTemp,new HighTemp(19));

		System.out.println(count + " days had a high less than 19");

	}

}

泛型方法的引用

interface MyFunc<T>{

	int func(T[] vals,T v);

}



class MyArrayOps{

	static <T> int countMatching(T[] vals,T v){

		int count =0;

		for (int i = 0; i < vals.length; i++) {

			if(vals[i] == v)count++;

		}

		return count;

	}

}



class LambdaRefMethod{

	static <T> int myOp(MyFunc<T> f, T[] vals,T v){

		return f.func(vals, v);

	}

	

	public static void main(String[] args) {

		Integer[] vals = {

				1,2,3,4,2,3,4,4,5

		};

		String[] strs ={

				"one","two","three","two"

		};

		

		int count;

		count = myOp(MyArrayOps::<Integer>countMatching,vals,4);

		System.out.println("vals contains " + count + " 4s");

		

		count = myOp(MyArrayOps::<String>countMatching,strs,"two");

		System.out.println("vals contains " + count + " 4s");

	}

}

import java.util.*;



class MyClass{

	private int val;

	MyClass(int v){ val = v;}

	int getVal(){ return val;}

}



class LambdaRefMethod{

	static int compareMC(MyClass a,MyClass b){

		return a.getVal() - b.getVal();

	}

	

	public static void main(String[] args) {

		ArrayList<MyClass> al = new ArrayList<>();

		

		al.add(new MyClass(1));

		al.add(new MyClass(4));

		al.add(new MyClass(2));

		al.add(new MyClass(9));

		al.add(new MyClass(3));

		al.add(new MyClass(7));

		

		// MyClass 既没有定义自己的比较方法,也没有实现Comparator接口,通过方法引用

		// 简化了代码

		MyClass maxValObj = Collections.max(al,LambdaRefMethod::compareMC);

		System.out.println("Maximum value is : "+maxValObj.getVal() );

	}

}

 构造函数的引用

interface MyFunc<R,T>{

	R func(T n);

}



class MyClass<T>{

	private T val;

	MyClass(T v){ val = v;}

    MyClass(){val = null;}

	T getVal(){return val;}

}



class MyClass2{

	String str;

	MyClass2(String s){str =s;}

	MyClass2(){str ="";}

	String getVal(){return str;}

}



interface MyArrayCreator<T>{

	T func (int n);

}



public class LambdaConstRef {

	static <R,T> R myClassFactory(MyFunc<R,T> cons,T v){

		return cons.func(v);

	}

	

	public static void main(String[] args) {

		MyFunc<MyClass<Double>,Double> myClassCons = MyClass<Double>::new;

		MyClass<Double> mc = myClassFactory(myClassCons, 100.1);

		System.out.println("val in mc is " + mc.getVal());

		

		MyFunc<MyClass2,String> myClassCons2 = MyClass2::new;

		MyClass2 mc2 = myClassFactory(myClassCons2, "lambda");

		System.out.println("str in mc2 is " + mc2.getVal());

		

		// 数组

		MyArrayCreator<MyClass2[]> mcArrayCons = MyClass2[]::new;

		MyClass2[] aa = mcArrayCons.func(2);

		aa[0] = new MyClass2("22");

		aa[1] = new MyClass2("122");

		System.out.println("aa[1] : " +aa[1].getVal());

				

		MyArrayCreator<MyClass<?>[]> mcArrayCons2 = MyClass<?>[]::new;

		MyClass<?>[] bb = mcArrayCons2.func(2);

		bb[0] = new MyClass<String>("22");

		bb[1] = new MyClass<String>("122");

		System.out.println("bb[1] : " +bb[1].getVal());

	}

}

java.util.function.* 中提供了 一些预定义的函数式接口。

UnaryOperator<T> : 对类型为T的对象应用一元运算,并返回类型为T的结果。包含的方法为apply()

BinaryOperator<T> :对类型为T的两个对象应用操作,并返回类型为T的结果,包含的方法为apply()

Consumer<T> :对类型为T的对象应用操作,包含的方法为accept()

Supplier<T> :返回类型为T的对象,包含的方法为get()

Function<T,R>:对类型为T的对象应用操作,返回类型为R的结果,包含的方法为apply()

Predicate<T> :确定类型为T的对象是否满足某种约束,并返回指出结果的布尔值,包含的方法为test()

import java.util.function.Function;

public class LambdaFunction {

	public static void main(String[] args) {

		Function<Integer,Integer> factorial = (n)->{

			int result = 1;

			for(int i =1;i<= n;i++){

				result =i * result;

			}

			return result;

		};

		

		System.out.println("the factorial of 3 : "+factorial.apply(3));

		System.out.println("the factorial of 5 : "+factorial.apply(5));

	}

}

import java.util.stream.*  在更高的抽象层次上对集合进行操作。

惰性求值,返回加工后的流。

及早求值返回另一个值。

import java.util.Comparator;

import java.util.List;

import java.util.stream.Collectors;

import java.util.stream.Stream;



class FunctionalProgramming {

	public static void main(String[] args) {

		// map

		List<String> s = Stream.of('a','b','c').map(c->(char)(c+4)+"").collect(Collectors.toList());

		// filter

		List<String> s2 = Stream.of("a","b","c","d").filter(str->str!="d").collect(Collectors.toList());

		// flatMap

		List<String> s3 = Stream.of(s,s2).flatMap(numbers->numbers.stream()).collect(Collectors.toList());

		System.out.println(s3);

		

		// reduce

		String all = s3.stream().reduce("all: ",(o,str)->o+str);

		System.out.println(all);		

		

		// min

		String min = s3.stream().min(Comparator.comparing(str->str.charAt(0))).get();

		System.out.println(min);

		

		// max

		String max = s3.stream().max(Comparator.comparing(str->str.charAt(0))).get();

		System.out.println(max);

	}

}

flatMap的实现与swift中差别很大

  

 

 总结:

缺点

1。两个不方便

2。没有语言层面的惰性求值

优点

1。lambda的加入 简化了代码,易读的代码可以更多地表达业务逻辑的意图,而不是它的实现机制。也更易于维护,更可靠,更不容易出错。

2。面向对象是对数据抽象,函数式编程则抽象了行为。让代码在多核CPU上高效运行。

 

 

其他主题 :

  类型修饰符: transient, volatile

  class T{

     transient int a;

     int b;

  }

  如果将T的对象写入永久存储区域时,不会保存a的内容,但会保存b的内容。

  volatile 告诉编译器,必须总是精确读取变量的最新值。

 

 instanceof:

 strictfp: 在java2 时,浮点计算模型扫尾宽松了一些, 这个修饰符告诉java定义内的所有浮点数都采用原始的计算模型。

 native: 声明本地代码方法。

     偶尔可能需要调用非JAVA语言编写的子例程,这类子例程作为可执行代码(对于正在使用的CPU和环境而言是可执行代码,即本地代码)而存在。一旦方法使用native声明,就可以从JAVA程序内部调用这些方法。

public class NativeDemo {

	int i;

	

	public static void main(String args[]){

		NativeDemo ob = new NativeDemo();

		

		ob.i = 10;

		System.out.println("This is ob.i before the native method :" + ob.i);

		ob.test();

		System.out.println("This is ob.i after the native method :"+ ob.i);

	}

	

	// declare native method

	public native void test();

	

	// load DLL that contains static method

	static{

		// 动态链接库,从JDK 8开始可以创建静态链接库

		System.loadLibrary("NativeDemo");

	}

}

 assert:

public class AssertDemo {

	static int val = 3;

	

	static int getNum(){

		return val--;

	}

	

	public static void main(String args[]){

		int n = 0;

		

		for(int i = 0; i<10;i++){

			n = getNum();

			assert n > 0 :"n is negative";

			System.out.println("n is "+ n);

		}

	}

}

Run -> Run Configurations -> Arguments页签 -> VM arguments文本框中加上断言开启的标志:-enableassertions 或者-ea 就可以了  

 

静态导入: 导入接口或类的静态成员

import static java.lang.Math.sqrt;

import static java.lang.Math.pow;

//import static java.lang.Math.*;



public class StaticImport {

	public static void main(String[] args) {

		double side1,side2;

		double hypot;

		

		side1 = 3.0;

		side2 = 4.0;

		hypot = sqrt(pow(side1,2) +pow(side2,2));

		

		System.out.println("Given sides of lengths " + side1 + " and " + side2 + " the hypotenuse is " + hypot);	

	}

}

 优点:简化并缩短了使用静态成员的代码

   缺点: 1,可读性变差(该静态成员来自哪里)

            2,可能的命名空间冲突

   仅针对重复使用某静态成员时设计,如执行一系列数学计算。但不能滥用这一特性。

通过this()调用重载的构造函数

class ThisConstructor {

	int a;

	int b;

	

	ThisConstructor(int i,int j){

		a = i; 

		b = j;

	}

	

	ThisConstructor(int i){

		a = i;

		b = i;

	}

	

	ThisConstructor(){

		a = 0;

		b = 0;

	}

}



class ThisConstructor2 {

	int a;

	int b;

	

	ThisConstructor2(int i,int j){

		a = i; 

		b = j;

	}

	

	ThisConstructor2(int i){

		this(i,i);

	}

	

	ThisConstructor2(){

		this(0);

	}

}

 

 this() 节省了代码,却会增加构造对象的开销

  适用于 包含大量初始化代码的构造函数,适用于创建少量对象的类,却不适合于那些只简单设置少量变量值的构造函数,不适合要大量创建对象的类。

  因super() 和 this() 都必须是构造函数的第一条语句,所有二者不能同时使用。

 

紧凑API配置文件

 JDK 8 新增功能,

 

内存管理 :

swift中的引用计数管理内存,会造成环形引用无法回收内存。用JAVA测试了一下,正常回收了

class Employee{

	Manager m;

	Employee(Manager m){

		this.m = m;

		System.out.println("init Employee");

	}

	protected void finalize(){

		System.out.println("deinit Employee");

	}

}

class Manager{

	Employee e = null;

	Manager(){

		System.out.println("init Manager");

	}

	void setEmployee(Employee e){

		this.e =e;

	}

	protected void finalize(){

		System.out.println("deinit Manager");

	}

}

public class GCTest {

	static void f(){

		Manager m = new Manager();

		Employee e = new Employee(m);

		m.setEmployee(e);

	}

	public static void main(String[] args) {

		f();

		System.gc();

	}

}

  

  

  

 

你可能感兴趣的:(java基础)