Java小白修炼手册--第二阶段--Java SE--反射、日期操作、Java8 Lambda

目录

反射

什么是反射

反射API

动态加载类

Class.forName( )

​动态创建对象

newInstance( )

动态调用方法

动态发现方法

动态执行方法

执行不可访问方法

日期操作

Date及其常用API

Java中的时间

Date类简介

setTime和getTime方法

Date重写toString

SimpleDateFormat

SimpleDateFormat简介

日期模式匹配字符

将Date格式化为String

将String格式化为Date

Calendar

Calendar简介

getInstance方法

设置日期及时间分量

获取日期及时间分量

getActualMaximum方法

add方法

setTime和getTime方法

Java8 Lambda

Lambda

Lambda表达式简介

Lambda表达式的结构

功能接口(函数接口)

@ FunctionalInterface

Lambda表达式与匿名内部类


反射

什么是反射

反射是Java系统的API,它允许程序在运行过程中取得任何一个已知名称的类的内部信息,包括其中的构造方法、声明的字段和定义的方法等
利用反射API可以实现动态执行:
动态加载类,获取信息
-动态创建对象
动态访问属性
-动态调用方法
动态执行:只是在JVM运行期间才确定的执行次序。
静态执行:是指编译以后就确定了程序的运行次序, JVM运行期间按照既定的次序执行。


反射API

Java反射API提供了动态执行能力ClassAPI :

  • java.lang.Class类,用于加载类和获取类的相关信息

Java反射API位于java.lang.reflect包中。主要包括以下几类:

  • Constructor类:用来描述一个类的构造方法。
  • Field类:用来描述一个类的成员变量。
  • Method类:用来描述一个类的方法。
  • Modifier类:用来描述类内各元素的修饰符。
  • Array :用来对数组进行操作。
    package reflect;
    
    import java.lang.reflect.Method;
    import java.util.Scanner;
    
    /**
     * java 反射机制
     * 
     * 反射机制是一种动态机制,允许我们程序在运行期间确定实例化对象的操作,方法调用的操作和
     * 属性赋值等操作。
     * 
     * 反射可以大大提高代码灵活度,但是也会带来更多的系统开销和降低运行性能。因此反射只在关
     * 键地方使用而不能过度依赖。
     * @author pc
     *
     */
    public class ReflectDemo1 {
    	public static void main(String[] args) throws ClassNotFoundException {
    		/*
    		 * Class类 称为:类的类对象
    		 * 该类的每一个实例用于表示已经被JVM加载的一个类,并且每个被JVM加载的类都有
    		 * 且只有一个类对象与之关联。
    		 * 通过类对象我们可以得知其表示的类的一切信息:类名,有哪些属性,方法,构造器
    		 * 并可以获取它们以便在运行期间调用。
    		 * 
    		 * 所以反射的第一步就是获取要操作的类的类对象。
    		 * 
    		 * 获取一个类的类对象有三种方式:
    		 * 1:类名.class
    		 *   例如:String.class
    		 *   	  ArrayList.class
    		 *   
    		 * 2:Class.forName(String className)  
    		 *   Class提供了一个静态方法forName,可以根据类的完全限定名(包名.类名)形式
    		 *   获取该类的类对象
    		 * 
    		 * 3:ClassLoader类加载器形式  
    		 */
    		
    		//获取String的类对象
    //		Class cls = String.class;//优点是简单直接,但是缺点是硬编码获取
    		/*
    		 * 该方法会抛出ClassNotFoundException,当给定的类的完全限定名无效时会抛出
    		 * 该异常。
    		 */
    //		Class cls = Class.forName("java.lang.String");
    //		Class cls = Class.forName("reflect.Person");
    		/*
    		 * java.lang.String
    		 * java.util.ArrayList
    		 * java.util.HashSet
    		 * java.util.HashMap
    		 * java.io.FileOutputStream
    		 * reflect.Person
    		 * 以上可參考
    		 */
    		System.out.println("请输入一个类名:");
    		Scanner scanner = new Scanner(System.in);
    		String className = scanner.nextLine();		
    		Class cls = Class.forName(className);
    		
    		//获取类名
    		String name = cls.getName();
    		System.out.println(name);
    		/*
    		 * Method类的每一个实例用于表示某个类中的某个方法
    		 * 
    		 * Class提供的方法:
    		 * Method[] getMethods()
    		 * 可以获取Class表示的类的所有公有方法
    		 */
    		System.out.println("获取本类所有公有方法,包含从超类继承的方法");
    		Method[] methods= cls.getMethods();
    		for(Method m : methods) {
    			System.out.println(m.getName());
    		}
    		
    		
    		System.out.println("获取本类定义的所有方法(不含有继承的方法):");
    		methods = cls.getDeclaredMethods();
    		for(Method m : methods) {
    			System.out.println(m.getName());
    		}
    	}
    }
    

     


动态加载类

Class.forName( )

动态加载类到内存万法区:
Class cls = Class.forName(类名)
1.类名是运行期间动态输入的类名,可以任何类名
2.返回值是一个引用,利用这个引|用指向的对象可以访问方法区中的类信息。
3.如果类名是错误的将出现"类没有找到"的异常

Java小白修炼手册--第二阶段--Java SE--反射、日期操作、Java8 Lambda_第1张图片
动态创建对象

newInstance( )

Class提供了动态创建对象的方法:
Object newInstance( )

  1. newInstance方法将调用类信息中的无参数构造器创建对象,如果没有无参数构造器,将抛出没有方法的异常。
  2. 如果需要调用有参数构造器,可以利用ConstructorAPI实现。
  3. 返回值弓|用动态创建的对象,因为可以是任何类型的对象,所以其类型为Object.
package reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;

/**
 * 使用反射机制实例化对象
 * @author pc
 *
 */
public class ReflectDemo2 {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		//硬编码方式实例化
		Person p = new Person();
		System.out.println(p);
		ArrayList a = new ArrayList();
		System.out.println(a);
		
		/*
		 * 使用反射机制:
		 * 1:加载要实例化对象的类的类对象
		 * 2:通过类对象的newInstance方法实例化 
		 */
		//实例化Person
		Class cls = Class.forName("reflect.Person");
		//需要注意newInstance方法要求Class表示的类必须有无参构造器
		Object obj = cls.newInstance();		
		System.out.println(obj);
		
		
		
		
		//硬编码方式调用有参数构造器
		Student stu = new Student("张三",22);
		System.out.println(stu);
		/*
		 * 利用有参构造器实例化对象
		 * 1:加载要实例化的类的类对象
		 * 2:通过类对象获取指定的构造方法
		 * 3:利用该构造方法实例化
		 */
		//1
		Class cls1 = Class.forName("reflect.Student");
		//2  Student(String name, int age)
		Constructor c = cls1.getConstructor(String.class,int.class);
		Object o1 = c.newInstance("李四",18);
		System.out.println(o1);
		
	}
}


动态调用方法


动态发现方法

Class提供了方法可以动态获取类的全部方法信息:
Method[ getDeclaredMethods( )

  1. Method代表方法信息,可以利用Method API获取方法对详细信息,如:方法名,返回值类型,参数类型列表等。
  2. 这个方法返回对数组代表当前类中对全部方法信息,每个元素代表一个方法信息。

动态执行方法

Method提供了动态执行一个方法的方法:
Object invoke(Object obj, Object.. args)

  1. obj代表一个对象,该对象上一定包含当前方法!否则将出现调用异常;如果obj为nul则抛出空指针异常;
  2.  args代表调用方 法时候传递的实际参数,如果没有参数可以不用或者传递null ,但是要注意参数的个数和类型必须和要调用的方法匹配,否则将出现参数错误异常;
  3. 返回值表示方法执行的结果 ,因为可能是任何类型,则其类型为Object ,调用没有返回值的方法则返回值为null ;
  4. 当被调用方法执行出现异常时候抛出Invoc ationTargetException。
    package reflect;
    
    import java.lang.reflect.Method;
    import java.util.Scanner;
    
    /**
     * 利用反射调用方法
     * @author pc
     *
     */
    public class ReflectDemo3 {
    	public static void main(String[] args) throws Exception {
    		Person p = new Person();
    		p.sayHello();
    		
    		/*
    		 * 利用反射调用方法:
    		 * 1:加载类对象
    		 * 2:实例化
    		 * 3:通过类对象获取要调用的方法
    		 * 4:调用该方法
    		 */
    		Scanner scanner = new Scanner(System.in);
    		System.out.println("请输入类名:");
    		String className = scanner.nextLine();
    		System.out.println("请输入方法名:");
    		String methodName = scanner.nextLine();
    		
    		//1
    //		Class cls = Class.forName("reflect.Person");
    		Class cls = Class.forName(className);
    		//2 Person o = new Person();
    		Object o = cls.newInstance();
    		//3 获取Person中无参数的sayHello方法
    //		Method method = cls.getMethod("sayHello");
    		Method method = cls.getMethod(methodName);
    		//4 o.sayHello()
    		method.invoke(o);
    	}
    }

     

执行不可访问方法

如果利用反射API调用了没有可访问权限时候会抛出异常:
IllegalAccessException,表示没有访问权限。
但是在Method方法上提供了解除访问限制的方法:
 setAccessible(boolean flag)
invoke之前使用这个方法可以解除访问限制,实现访问没有权限的方法。
注意:这个功能破坏了面向对象原有的封装性,利用它但是却能写出一些特殊功能代码,有些面试官也将这个知识点作为反射是否熟悉的标志!
 

package reflect;

import java.lang.reflect.Method;

/**
 * 使用反射机制调用私有方法
 * 这样做可能破坏类的封装性
 * @author pc
 *
 */
public class ReflectDemo5 {
	public static void main(String[] args) throws Exception {
//		Person p = new Person();
//		p.dosome();//编译不通过
		
		Class cls = Class.forName("reflect.Person");
		Object o = cls.newInstance();
		//获取私有方法dosome
		Method m = cls.getDeclaredMethod("dosome");
		m.setAccessible(true);//强行访问!
		m.invoke(o);
		
		
	}
}

日期操作

Date及其常用API

Java中的时间

  • Java中的时间使用标准类库的Date类表示,是用距离一个固定时间点的毫秒数(可正可负, long类型)表达一个特定的时间点;
  • 固定的时间点叫纪元( epoch ), 是UTC时间1970年1月1日00:00:00 ;
  • UTC ( Universal Time Coordinated世界调整时间)与GMT ( Greenwich Mean Time格林威治时间)一样,是一种具有实际目的的科学标准时间。

Date类简介

  • java.util.Date类封装日期及时间信息。
  • Date类的大多数用于进行时间分量计算的方法已经被Calendar取代。
Date date = new Date();
//系统当前的日期及时间信息
System.out.println(date);
// Sun Jan 06 11:52:55 CST 2013
long time = date.getTime);
//1970年1月1日至今的毫秒数


setTime和getTime方法

/**使用setTime和getTime设置及获取时间*/
public void testSetTime() { 
Date date = new Date();
//输出当天此时此刻的日期和时间
System.out.println(date);
long time = date.getTime();
//增加一天所经历的毫秒数
time
+=
60 *
60
* 24 * 1000;
date. setTime(time);
//输出明天此时此刻的日期和时间
System.out.println(date);
/**
获取当前系统时间*/
public void testGetTime() {
Date date = new Date();
System.out.println(date);
//1970年1月1日零时距此刻的毫秒数
long time = date.getTime();
System.out.println(time);


Date重写toString

  • Date重写了toString(方法,用一个字符串来描述当前Date对象所表示的时间。格式如下:
  • Mon Feb 17 15:36:55 CST 2014
     

 


SimpleDateFormat

SimpleDateFormat简介

java.text.SimpleDateFormat是一个以与语言环境有关的方式来格式化和解析日期的具体类。它允许进行格式化(日期->文本)、解析(文本->日期)和规范化

  • 构造方法
  • SimpleDateFormat ( )
  • -SimpleDateFormat ( String pattern ) //用给定的模式和默认语言环境的日期格式符号构造SimpleDateFormat
  • 方法
  • -final String format ( Date date) //Date =>String
  • - Date parse(String source) throws ParseException //String => Date


日期模式匹配字符

Java小白修炼手册--第二阶段--Java SE--反射、日期操作、Java8 Lambda_第2张图片


将Date格式化为String

/**日期格式化*/
public void testFormat() {
    SimpleDateFormat sdf = new SimpleDateFormat(' 'yy- MM-dd HH:mm:ss' );
    Date date = new Date();
    String dateStr = sdf.format(date);
    System.out.println(dateStr);
}


将String格式化为Date

/**和format方法相反, parse方法用于按照特定格式将表示时间
的字符串转换为Date对象*/
public void testParse() throws Exception {
        String str = "2013-12-25";
        SimpleDateFormat sdf =    new SimpleDateFormat( "yyy-MM-dd");
        Date date = sdf.parse(str);
        System.out.println(date);
}

Calendar


Calendar简介

  • java.util.Calendar类用于封装日历信息,其主要作用在于其方法可以对时间分量进行运算;
  • Calendar是抽象类,其具体子类针对不同国家的日历系统,其中应用最广泛的是GregorianCalendar (格里高里历,即通用的阳历) , 对应世界上绝大多数国家/地区使用的标准日历系统。

getInstance方法

Calendar提供了一个类方法getInstance ,以获得此类型的一个通用的对象
Calendar的getInstance方法返回一个Calendar对象其日历字段已由当前日期和时间初始化

 Calendar C = Calendar.getInstance(;
/**使用alendar及子类获取时间*/
public void testGetInstance() {
    Calendar C = Calendar.getInstance(;
    //输出Calendar对象所属的实际类型
    System.out.println(c.getClass).getName();
    // getTime方法返回对应的Date对象
    System.out.println(c.getTime();
    //创建GregorianCalendar对象
    GregorianC alendar c1 = new Gregorian alendar(2013, Calendar.DECEMBER,25); 
    System.out.println(c1.getTime();
}

设置日期及时间分量

/**设置日期及分量*/
public void testSet() {
    Calendar C = Calendar.getInstance();
    c.set(C alendar.YEAR, 2014);
    c.set(C alendar.MONTH, Calendar.DEC EMBER);
    c.set(Calendar.DATE, 25);
    System.out. println(c.getTime());
    //Thu Dec 25 16:02:08 CST 2014
    c.set(C alendar.DATE, 32);
    System.out.println(c.getTime()); 
    //Thu Jan 01 16:02:08 CST 2015
}


获取日期及时间分量

使用Calendar提供的get方法及- -些常量可以获取日期及时间分量

  • static int YEAR指示年份的字段数字
  • static int MONTH指示月份的字段数字
  • static int DATE指示一个月份中的第几天
  • static int DAY OF WEEK 指示一个星期中的某天, 1为星期日
/**获取时间及分量*/
    public void testGet() {
    Calendar C = Calendar.getInstance();
    C. set(C alendar.YEAR, 2014);
    c.set(C alendar. MONTH, Calendar.DECEMBER); 
    C. set(Calendar.DATE, 25);
    int dayOfWeek = c.get(Calendar.DAY_ OF_ _WEE K);
    System.out.println(dayOfWeek);
    //输出为5,表示周四,周日为每周的第1天.
    }

getActualMaximum方法

int getActualMaximum ( int field )给定此Calenda的时间值,返回指定日历字段可能拥有的最大值,

例如:
 

int year = 2014;
Calendar C = Calendar.getInstance();
c.set(C alendar.YEAR, year);
c.set(C alendar.DATE, 1);
for (int month = Calendar.JANUARY;
        month <= Calendar.DEC EMBER; month+ +)
    C. set(C alendar.MONTH, month);
    System.out.println(year +"年"
                        +(month+1)+"月: "
                        + c.getActualMaximum (Calendar.DATE+ "天");
        }
    }

add方法

void add ( int field,int mount )为给定的时间分量的值加上给定的值,若给定的值为负数则是减去给定的值

/**输出一年后再减去3个月的日期*/
public void testAdd(){
    Calendar calendar = Calendar.getInstance();
    calendar.add(C alendar.YEAR, 1);/加一年
    calendar.add(C alendar.MONTH, -3);//减3个月
    System.out.println(" year:" + calendar.get( alendar.YEAR));

    System.out.println(" month:" +(calendar.get(C alendar.MONTH)+ 1));

    System.out.println(" day:" + calendar.get( alendar.DAY_ OF_ .MONTH));
}

setTime和getTime方法

  • Date getTime( )使用Date描述Calendar表示的日期并返回
  • void setTime(Date d)使Calendar表示Date所描述的日期
/**.通过Date对象设置日期,在获取日期*/
public void testsetTimeAndGetTime(){
    Calendar calendar = Calendar.getInstance();
    Date date = new Date(); 
    calendar.setTime(date);
    date = calendar.getTime();
}

Java8 Lambda


Lambda


Lambda表达式简介

  • Lambda表达式是一种"匿名函数" (对Java而言这并不完全正确编译后还会转换为类) , 简单地说它是没有声明的方法:即没有访问修饰符、返回值声明和名字。
  • Lambda表达式为Java添加了缺失的函数式编程特点。


Lambda表达式的结构

  • Java中的Lambda表达式语法: (argument) -> {body}
  •          一个Lambda表达式可以有零个或多个参数
  • 参数的类型既可以明确声明, 也可以根据上下文来推断。
  •         例如: (int a)与(a)效果相同
  • 所有参数需包含在圆括号内,参数之间用逗号相隔。
  •         例如:(a,b)或(inta,intb)或(Stringa,intb,floatc)
  • 空圆括号代表参数集为空。
  •         -例如:()-> 42
  • 只有一个参数,且其类型可推导时,圆括号( )可省略。
  •        -例如: a-> return a*a
  • Lambda表达式的主体可包含零条或多条语句
  • 如果Lambda表达式的主体只有一 条语句,花括号}可省略,如果返回值需要省略return. 如果Lambda表达式的主体包含一条以上语句,则表达式必须包含在花括号{}中(形成代码块)。
  • 匿名函数的返回类型与代码块的返回类型一致,若没有返回则为空
(inta,intb)->{returna+b;}
() -> System. out. println("Hello World");
(String s) -> { System . out. println(s); }
() -> 42
() -> { return 3.1415 } ;

功能接口(函数接口)

  • 函数式接口是只包含一个抽象方法声明的接口。
  • java.lang.Runnable就是一种函数式接口 ,在Runnable接中只声明了一个方法void run() ,相似地,ActionListener接口也是一种函数式接口
  • 般可以使用匿名内部类来实例化函数式接口的对象有了Lambda表达式,这一方式可以得到简化。
//通过Lambda表达式创建Runnable接口的实例:
Runnabler = () -> System.out.printIn("hello world ");

//相当于匿名内部类创建Runnable接口的实例:
Runnabler = newRunnable(){
    public void run({
    System.out.println("hello world");
    }
};
//当不指明函数式接口时,编译器会自动解释这种转化:
Thread t = new Thread( 
        () -> System.out.printn("hello world")
 );
/**Java编译器根据构造器参数 new Thread(Runnable r)
推断整个Lambda表达式的类型是Runnable类型的*/

@ FunctionalInterface

  • @FunctionalInterface是Java 8新加入的一-种注解,用于指明该注解类型声明是根据Java语言规范定义的函数式接口。
  • 当接口不是有效的函数式接口时,可以使用@FunctionalInterface注解时候将出现编译错误。

错误:

Unexpected @ FunctionalInterface annotation
@FunctionalInterface ^ WorkerInterface is not a functional
interface multiple
non-overriding abstract methods found in interface
WorkerInterface 1 error

Lambda表达式与匿名内部类

  • 使用匿名类与Lambda表达式的一大区别在于关键词的使用。
  • 对于匿名类,关键词this解读为匿名类,而对于Lambda表达式,关键词this解读为写就Lambda的外部类。
  • Java编译器编译Lambda表达式并将他们转化为类里面的私有函数。

 

你可能感兴趣的:(Java小白修炼手册--第二阶段--Java SE--反射、日期操作、Java8 Lambda)