【集合】:
Collection接口 (Collection接口是集合类的根接口,Java中没有提供这个接口的直接的实现类。但是却让其被继承产生了两个接口,就是Set和List) | ||
Set接口(无序集合,不允许重复,检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变) | HashSet(以哈希表的形式存放元素,插入删除速度很快) | LinkedHashSet(有序集合) |
SortedSet | TreeSet(排序集合) | |
EnumSet |
| |
Queue(队列) | ... |
|
... |
| |
List接口(有序集合,可以有重复元素,提供了按索引访问的方式。和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变) | Vector(线程安全的,但是效率低) | Stack(线程安全的,但是效率低;是Vector的一个子类,它实现了标准的后进先出堆栈) 线程不安全的类都可以配合Collections得到线程安全的类 |
ArrayList(动态数组) |
| |
LinkedList(链表、队列、堆栈) |
Map(无序集合) | |
HashMap (Key不允许重复;快速访问,取得数据的顺序随机,非同步) | LinkedHashMap(有序集合,比HashMap慢,保存了记录的插入顺序,遍历时先得到的记录肯定是先插入的,有HashMap的全部特性) |
Hashtable(Key不允许重复;是HashMap的线程安全版,支持线程的同步,即同一时刻只有一个线程能写Hashtable,效率低) ConcurrentHashMap线程安全且锁分离 | Properties (Properties是Hashtable的子类。它用于维护键的列表,其中键是String,值也是String。) |
SortedMap | TreeMap(排序集合,默认是按键值的升序排序,非同步;实现SortedMap接口,能把保存的记录根据键排序) |
WeakHashMap |
|
IdentityHashMap |
|
EnumMap |
|
//Set集合(遍历方式:迭代器迭代/forEach循环遍历,与list方式一样):
Set set = new HashSet();
set.add("Bernadine");
set.add("Clara");
/*set接口中不能加入重复元素,但是可以排序--HashSet散列存放;TreeSet排序集合*/
Set set= new TreeSet(set); //排序集合:根据内容自动排序(不是按照插入顺序)
// List集合:
/*ArrayList和Vector比较:ArrayList采用异步处理的方式,性能高,属于非线程安全;Vector采用同步处理的方式,性能低,属于线程安全。*/
/*ArrayList和LinkedList在用法上没有区别,但是在功能上还是有区别的。LinkedList经常用在增删操作较多而查询操作很少的情况下,ArrayList则相反。*/
List list = new Vector(); //java.util.Vector;
List<Object> list=new ArrayList<Object>(); // java.util.ArrayList; --使用泛型指定类型为 Object(不使用泛型:List list=new ArrayList();)
list.add(“***”); //写入数据
list.remove(0); //删除当前元素
list.indexOf("a"); //查找制定的对象是否存在(返回int)
list.isEmpty(); //判断集合是否为空(返回booole)
/*遍历list集合-1(使用迭代器迭代),Iterator是专门的迭代输出接口,迭代输出就是将元素一个个进行判断,判断其是否有内容,如果有则把内容取走*/
Iterator<User> it=list.iterator(); //不能在迭代输出的时候进行iter.remove()删除操作,会报错
while (it.hasNext()) { //使用hasNext()检查序列中是否还有元素(判断是否下一个元素为空)
User user1 = (User) it.next(); // 使用next()获得序列中的下一个元素
System.out.println("username:"+user1.getUsername());
}
/*遍历list集合-2 (forEach循环遍历)*/
for (String s : list) {
System.out.println(s);
}
/*遍历list集合-3 (for循环遍历)*/
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i).getUsername());
}
//map集合:
Map<String, User> map=new HashMap<String, User>(); //java.util.HashMap; --使用泛型指定类型为String,User(不使用泛型:Map map=new HashMap();)
map.containsKey(users.getUsername()); //containsKey()方法用于检查特定键是否被映射到 HashMap,它将key元素作为参数,如果该元素在map中映射,则返回True
map.put(users.getUsername(), users); //写入数据
map.put("1", 1);
int i = (int) map.get("1"); //提取键值
map.containsKey("1"); //看key是不是存在 返回boolean
map.containsValue(1); //看value是不是存在,返回boolean
/*遍历map集合-1 (map无法直接使用Iterator遍历,需要先获取set视图)*/
Set<String> set=map.keySet(); //第一种:map.keySet()可以将所有的键都提取出来,返回的是一个Set集合
Iterator<String> it=set.iterator(); //使用set集合调用迭代器Iterator来进行输出
while (it.hasNext()) {
String key = (String) it.next();
User user=map.get(key);
System.out.println("username:"+user.getUsername());
}
Set set=map.entrySet(); //第二种:使用EntrySet的Iterator
Iterator it = set.iterator();
while(it.hasNext()){
Entry e =(Entry) it.next();
System.out.println(e.getKey()+":"+e.getValue());
}
/*遍历map集合-2 */
for (String key : map.keySet()) { //第一种:forEach直接使用HashMap的keyset
System.out.println("key:"+key+"value:"+map.get(key));
}
for(Entry<String, String> entry : map.entrySet()){ //第二种:forEach循环遍历HashMap的entrySet
System.out.println("key:"+entry.getKey()+" value:"+entry.getValue());
}
/*遍历map集合-3(只取到value) */
for (String s : map.values()) { //map.values();是返回所有值,返回是一个Collection 集合
System.out.println(s);
}
【序列化】:
IO流示例:CSDN博客 https://blog.csdn.net/qq_36095102/article/details/99735418
字符流和字节流区别:
//字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串,而字节流处理单元为1个字节,操作字节和字节数组;
//读文本的时候用字符流,例如txt文件,读非文本文件的时候用字节流,例如mp3;
//字节流提供了处理任何类型的IO操作的功能,但不能直接处理Unicode字符,而字符流就可以。
缓冲流原理:
1)缓冲区的出现:提高了流的读写效率,所以在缓冲区创建前,要先创建流对象。即先将流对象初始化到构造函数中。
2)缓冲技术原理:此对象中封装了数组,将数据存入,再一次性取出。
3)写入流缓冲区BufferedWriter
序列化和反序列化:
// 将程序中的对象写入文件,之后再从文件中把对象读出来重新建立,这就是所谓的对象序列化。Java中引入它主要是为了RMI(Remote Method Invocation)和Java Bean所用。
/*Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以采用默认的序列化方式 */
/*只有实现了Serializable和Externalizable接口的类的对象才能被序列化。 */
/*序列化(Serialization):是将对象的状态信息转换为可以存储或传输的形式的过程;序列化时,对象将其当前状态写入到临时或持久性存储区;可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。*/
transient int k = 15; //实现Serilizable接口时,将不需要序列化的属性前添加关键字transient,序列化对象的时候,该属性就不会序列化到指定的目的地中
/*读取(反序列化):把字节序列恢复为对象的过程称为对象的反序列化*/
FileInputStream fis=new FileInputStream(new File("C:/test.text")); //创建一个对象输入流
ObjectInputStream ois=new ObjectInputStream(fis);
Object obj=ois.readObject(); //通过对象输入流readObject()方法读取数据
System.out.println(obj);
/*写入(序列化):将对象状态转换为可保持或传输格式的过程*/
FileOutputStream fos=new FileOutputStream(new File("C:/test.text"));
ObjectOutputStream oos=new ObjectOutputStream(fos); //创建一个对象输出流
oos.writeObject("***"); //过对象输出流的writeObject( )方法写对象
oos.flush();
【递归 (Recursion) 】:
//使用范围:当一个功能被重复使用,而每一次使用该功能时的参数不确定,都由上次的功能元素结果来确定。其实递归就是在栈内存中不断的加载同一个函数。
//1.输出指定路径下的所有文件和文件夹
public static void showDir(File file){
System.out.println(file); //打印目录
File[] files=file.listFiles();
for(int i=0;i<files.length;i++){
if(files[i].isDirectory()){ //判断是否是目录(文件夹)
showDir(files[i]); //递归
}else{
System.out.println(files[i]); //打印指定路径下的所有文件名称
}
}
}
//2.递归运算,以二进制方法为例
public static void toBin(int num){
if(num>0){
toBin(num/2); //递归
System.out.println(num+":"+num%2); //两数相除后的余数(会先打印最后的结果,然后倒序输出!)
}
}
//3.求和运算
public static int getSum(int n){
if(n==1){
return n;
}else{
return n+getSum(n-1);
}
}
【多线程 (Multi Thread) 】:
多线程定义:指的是这个程序(一个进程)运行时产生了不止一个线程(一个进程在其执行过程中可以产生多个线程)
进程:是程序的一次动态执行过程
线程:是进程中执行运算的最小单位,一个进程在其执行过程中可以产生多个线程,而线程必须在某个进程内执行。
多线程:线程是进程内部的一个执行单元,可完成一个独立的任务的顺序控制流程,如果在一个进程中同时运行了多个线程,用来完成不同的工作,则称之为多线程。
并行:多个cpu实例或者多台机器同时执行一段处理逻辑,是真正的同时。
并发:通过cpu调度算法,让用户看上去同时执行,实际上从cpu操作层面不是真正的同时。并发往往在场景中有公用的资源,那么针对这个公用的资源往往产生瓶颈,我们会用TPS或者QPS来反应这个系统的处理能力。
线程安全:经常用来描绘一段代码。指在并发的情况之下,该代码经过多线程使用,线程的调度顺序不影响任何结果。这个时候使用多线程,我们只需要关注系统的内存,cpu是不是够用即可。反过来,线程不安全就意味着线程的调度顺序会影响最终结果
同步:Java中的同步指的是通过人为的控制和调度,保证共享资源的多线程访问成为线程安全,来保证结果的准确。
目的:就是"最大限度地利用CPU资源",当某一线程的处理不需要占用CPU而只和I/O,OEMBIOS等资源打交道时,让需要占用CPU资源的其它线程有机会获得CPU资源。从根本上说,这就是多线程编程的最终目的。要通过不断切换需要运行的线程让其运行的方式就叫并发(concurrent)。而在多CPU系统中,可以让两个以上的线程同时运行,这种可以同时让两个以上线程同时运行的方式叫做并行(parallel)。
线程完整的生命周期:
新建状态: 一个新产生的线程从新状态开始了它的生命周期。它保持这个状态直到程序start这个线程。
运行状态:当一个新状态的线程被start以后,线程就变成可运行状态,一个线程在此状态下被认为是开始执行其任务
就绪状态:当一个线程等待另外一个线程执行一个任务的时候,该线程就进入就绪状态。当另一个线程给就绪状态的线程发送信号时,该线程才重新切换到运行状态。
休眠状态: 由于一个线程的时间片用完了,该线程从运行状态进入休眠状态。当时间间隔到期或者等待的事件发生了,该状态的线程切换到运行状态。
终止状态: 一个运行状态的线程完成任务或者其他终止条件发生,该线程就切换到终止状态。
多线程三种实现方法:
1)继承Thread类,重写run()方法
2)实现Runnable接口,并实现该接口的run()方法
3)使用ExecutorService、Callable、Future实现有返回结果的多线程(实现Callable接口,重写call()方法)
其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。run()方法可以产生必须退出的标志来停止一个线程.
同步的实现方面有两种:
synchronized、wait与notify
继承Thread类的方法尽管被我列为一种多线程实现方式,但Thread本质上也是实现了Runnable接口的一个实例,它代表一个线程的实例,并且,启动线程的唯一方法就是通过Thread类的start()实例方法。start()方法是一个native方法,它将启动一个新线程,并执行run()方法。这种方式实现多线程很简单,通过自己的类直接extend Thread,并复写run()方法,就可以启动新线程并执行自己定义的run()方法。例如:
//继承Thread类,重写run()方法
public class MyThread extends Thread {
public void run() {
System.out.println("MyThread.run()");
}
}
//在合适的地方启动线程如下:
MyThread myThread1 = new MyThread();
MyThread myThread2 = new MyThread();
myThread1.start();
myThread2.start();
设计4个线程:其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序。
以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。
public class ThreadTest1{
private int j;
public static void main(String args[]){
ThreadTest1 tt=new ThreadTest1();
Inc inc=tt.new Inc();
Dec dec=tt.new Dec();
for(int i=0;i<2;i++){
Thread t=new Thread(inc);
t.start();
t=new Thread(dec);
t.start();
}
}
private synchronized void inc(){
j++;
System.out.println(Thread.currentThread().getName()+"-inc:"+j);
}
private synchronized void dec(){
j--;
System.out.println(Thread.currentThread().getName()+"-dec:"+j);
}
//2.实现Runnable接口,并实现该接口的run()方法
class Inc implements Runnable{
public void run(){
for(int i=0;i<100;i++){
inc();
}
}
}
class Dec implements Runnable{
public void run(){
for(int i=0;i<100;i++){
dec();
}
}
}
}
【泛型 (Generics) 】:
泛型定义:
本质是参数化类型,当类中操作的引用类型不确定时引用 (这样可以避免强转的麻烦,而且将运行问题转移到的编译时期)
//也就是说操作的数据类型被指定为一个参数,使代码可以应用于多种类型
//将对象的类型作为参数,指定到其他类或者方法上,从而保证类型转换的安全性和稳定性,这就是泛型。
语法:
类1或者接口<类型实参> 对象=new 类2<类型实参>( );
例:List<NewTitle> list=new ArrayList<NewTitle>( );
//1.定义泛型类的语法:访问修饰符 class className<TypeList> //--TypeList:表示类型参数列表
public class GenericClass<T>{......}
//创建泛型类实例的语法:new className<TypeList>(argList); //--TypeList:表示定义的类型参数列表 , argList : 表示实际传递的类型参数列表
GenericClass<String> genc = new GenericClass<String>("this is String object")
//继承泛型类的语法:访问修饰符 class 子类<T> extends 父类<T>{ }
public class 子类<T> extends GenericClass<T>{ }
//2.定义泛型接口的语法:访问修饰符 interface interfaceName<TypeList> ----TypeList:表示由逗号分隔的一个或多个类型参数列表
public interface TestInterface<T>{
public T print(T t);
}
//泛型类实现泛型接口的语法:访问修饰符 class className<TypeList> inplements interfaceName<TypeList>
public class className<TypeList> inplements interfaceName<TypeList>
//3.定义泛型方法的语法:访问修饰符 <类型参数> 返回值 方法名(类型参数列表)
public <String> void showName(String s){ } //注意:泛型方法中,类型变量是放置在访问修饰符与返回值之间
public static <String> void showName(String s){ }
【枚举(enum)】:
定义:指由一组固定的常量组成的类型(使用关键字enum定义,继承java.lang.Enum)
Enum 一般用来表示一组相同类型的常量
//枚举定义语法:
[访问修饰符] enum enumName{ //enum是关键字(类似于class关键字)
enum1, enum2; //枚举常量列表,枚举常量之间以逗号隔开(枚举中,如果除了定义枚举常量,还定义了其他成员,则枚举常量列表必须以分号(;)结尾)
[field , method] //表示其他的成员,包括构造方法,置于枚举常量的后面
}
//不使用枚举时:
public class Direction {
public static final int EAST = 0;
public static final int WEST = 1;
public static final int SOUTH = 2;
public static final int NORTH = 3;
}
/* 用法一:常量 */
public enum DirectionEnum {
EAST, WEST, NORTH, SOUTH
}
/* 用法二:switch (JDK1.6之前的switch语句只支持int,char,enum类型)*/
public enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
//用法三:自定义方法(必须在enum实例序列的最后添加一个分号,而且Java要求必须先定义enum实例)
public enum Color{
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
/* 1.向枚举中添加新方法 */
public static String getName(int index) {
for (Color c : Color.values()) {
//......
}
return null;
}
/* 2.覆盖枚举的方法 */
@Override
public String toString() {
return this.index + "_" + this.name;
}
}
//用法三调用
public static void main(String[] args){
System.out.println(Color.RED.toString());
}
【单例模式 (SingletonPattern) 】:
参考: https://www.runoob.com/design-pattern/singleton-pattern.html
单例模式:常见23种设计模式之单例模式。
3个特点:
①、单例类只能有一个实例。
②、单例类必须自己创建自己的唯一实例。
③、单例类必须给所有其他对象提供这一实例。
(构造函数是私有的,方法是static的)
定义:一个类有且仅有一个实例,并且自行实例化向整个系统提供。
目的:是保证整个应用中只存在类的唯一个实例。
比如我们在系统启动时,需要加载一些公共的配置信息,对整个应用程序的整个生命周期中都可见且唯一,这时需要设计成单例模式。如:spring容器,session工厂,缓存,数据库连接池等等。
优点:该类只存在一个实例,节省系统资源;对于需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
缺点:不能外部实例化(new),调用人员不清楚调用哪个方法获取实例时会感到迷惑,尤其当看不到源代码时。
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
何时使用:当您想控制实例数目,节省系统资源的时候。
意义:单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。
分类:
懒汉式单例(实现线程安全三种方式:在getInstance方法上加同步、双重检查锁定、静态内部类)
饿汉式单例
登记式单例(可忽略)
( 始终是一个对象实例.它对外不提供构造函数,因此我们不能够同时产生多个对象. )
参考:https://blog.csdn.net/emira_j/article/details/52447390
应用实例:Windows 是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
public class SingleObject {
//创建 SingleObject 的一个对象
private static SingleObject instance = new SingleObject();
//让构造函数为 private,这样该类就不会被实例化
private SingleObject(){}
//获取唯一可用的对象
public static SingleObject getInstance(){
return instance;
}
public void showMessage(){
System.out.println("Hello World!");
}
}
//从 singleton 类获取唯一的对象:
public class SingletonPatternDemo {
public static void main(String[] args) {
//不合法的构造函数
//编译时错误:构造函数 SingleObject() 是不可见的
//SingleObject object = new SingleObject();
//获取唯一可用的对象
SingleObject object = SingleObject.getInstance();
//显示消息
object.showMessage();
}
}
//单例模式的几种实现方式:
//懒汉式—线程不安全(懒汉式单例开始没有实例化对象,用到时才实例化,比较节省空间)
//懒汉式—线程安全(+synchronized 修饰符)
//饿汉方式
//双检锁式
//登记式
//枚举
你用杯子喝可乐,喝完了不刷,继续去倒果汁喝,就是单例。
你用杯子喝可乐,直接扔了杯子,换个杯子去倒果汁喝,就是多例。
①. 什么是单例多例:
所谓单例就是所有的请求都用一个对象来处理,比如我们常用的service和dao层的对象通常都是单例的,而多例则指每个请求用一个新的对象来处理,比如action;
②. 如何产生单例多例:
在通用的SSH中,单例在spring中是默认的,如果要产生多例,则在配置文件的bean中添加scope="prototype";
③. 为什么用单例多例:
之所以用单例,是因为没必要每个请求都新建一个对象,这样子既浪费CPU又浪费内存;
之所以用多例,是为了防止并发问题;即一个请求改变了对象的状态,此时对象又处理另一个请求,而之前请求对对象状态的改变导致了对象对另一个请求做了错误的处理;
用单例和多例的标准只有一个:
当对象含有可改变的状态时(更精确的说就是在实际应用中该状态会改变),则多例,否则单例;
④. 何时用单例?何时用多例?
对于struts2来说,action必须用多例,因为action本身含有请求参数的值,即可改变的状态;
而对于STRUTS1来说,action则可用单例,因为请求参数的值是放在actionForm中,而非action中的;
另外要说一下,并不是说service或dao一定是单例,标准同第3点所讲的,就曾见过有的service中也包含了可改变的状态,同时执行方法也依赖该状态,但一样用的单例,这样就会出现隐藏的BUG,而并发的BUG通常很难重现和查找;
/懒汉式单例类.在第一次调用的时候实例化自己
public class Singleton {
private static Singleton single=null;
private Singleton() {}
//静态工厂方法
public static Singleton getInstance() {
if (single == null) {
synchronized(Singleton.class){
single = new Singleton();
}
}
return single;
}
}
【反射 (Reflection) 】:
参考:https://blog.csdn.net/huangliniqng/article/details/88554510
概念:反射就是把java类中的各种成分映射成一个个的Java对象。
Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在。
反射机制:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
使用条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)
(要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.)
public static void main(String[] args) {
try {
Class cl=Class.forName("com.cn.yx.reflect.ReflectBook"); //1.1 获取类名cl
ReflectBook rbook=new ReflectBook(); //1.2 获取类名cl
Class cl2=rbook.getClass();
Constructor[] constructors=cl.getDeclaredConstructors(); //2.1通过getDeclaredConstructors可以返回类的所有构造方法,返回一个数组...
for (int i = 0; i < constructors.length; i++) {
System.out.print(Modifier.toString(constructors[i].getModifiers())+ "\t参数:"); //通过getModifiers可以得到构造方法的类型public
Class[] parametertypes=constructors[i].getParameterTypes(); //getParameterTypes可以得到构造方法的所有参数,返回的是一个Class数组
for (int j = 0; j < parametertypes.length; j++) {
System.out.print(parametertypes[j].getName()+"\t");
}
System.out.println(constructors[i]); //打印构造方法
}
//2.2也可以通过getConstructors方法获取类中 所有的public类型的构造方法(与上面获取方法一样)......
//得到类的实例,主要借助于newInstance方法
Class[] p={int.class,String.class};
Constructor constructor=cl.getDeclaredConstructor(p); //2.3或者通过getDeclaredConstructor()方法传参获取特定参数类型的构造方法,返回的是一个Class对象...
// constructor.setAccessible(true); //调用私有构造方法加这个即可
constructor.newInstance(26,"杨旭"); //调用有两个参数的构造方法
//3.通过 getDeclaredMethod方法获取到这个私有方法,第一个参数是方法名,第二个参数是参数类型
Class[] p4 = {String.class};
Method method=cl.getDeclaredMethod("welcome", p4); //获得私有方法welcome()
method.setAccessible(true);
Object arg1s[]={"欢迎关注!!!"};
method.invoke(rbook, arg1s); //过invoke方法执行,invoke需要两个参数一个是类的实例,一个是方法参数
//4.通过反射得到类的实例之后先获取字段
Field field = cl.getDeclaredField("name");
field.setAccessible(true);
field.set(rbook,"代码");
System.out.println("打印name值为:"+field.get(rbook).toString());
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch...
}
定义:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
链接详解:https://blog.csdn.net/misswwg/article/details/51659812
那么什么是Java的反射呢?
要让Java程序能够运行,那么就得让Java类要被Java虚拟机加载。Java类如果不被Java虚拟机加载,是不能正常运行的。现在我们运行的所有的程序都是在编译期的时候就已经知道了你所需要的那个类的已经被加载了。
Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、探知、自审。使用在编译期并不知道的类。这样的特点就是反射。
那么Java反射有什么作用呢?
假如我们有两个程序员,一个程序员在写程序的时候,需要使用第二个程序员所写的类,但第二个程序员并没完成他所写的类。那么第一个程序员的代码能否通过编译呢?这是不能通过编译的。利用Java反射的机制,就可以让第一个程序员在没有得到第二个程序员所写的类的时候,来完成自身代码的编译。
Java的反射机制它知道类的基本结构,这种对Java类结构探知的能力,我们称为Java类的“自审”。大家都用过Jcreator和eclipse。当我们构建出一个对象的时候,去调用该对象的方法和属性的时候。一按点,编译工具就会自动的把该对象能够使用的所有的方法和属性全部都列出来,供用户进行选择。这就是利用了Java反射的原理,是对我们创建对象的探知、自审。
Class类
要正确使用Java反射机制就得使用java.lang.Class这个类。它是Java反射机制的起源。当一个类被加载以后,Java虚拟机就会自动产生一个Class对象。通过这个Class对象我们就能获得加载到虚拟机当中这个Class对象对应的方法、成员以及构造方法的声明和定义等信息。
反射API
u反射API用于反应在当前Java虚拟机中的类、接口或者对象信息
u功能
—获取一个对象的类信息.
—获取一个类的访问修饰符、成员、方法、构造方法以及超类的信息.
—检获属于一个接口的常量和方法声明.
—创建一个直到程序运行期间才知道名字的类的实例.
—获取并设置一个对象的成员,甚至这个成员的名字是在程序运行期间才知道.
—检测一个在运行期间才知道名字的对象的方法
..........
反射机制是框架技术的原理和核心部分。通过反射机制我们可以动态的通过改变配置文件(以后是XML文件)的方式来加载类、调用类方法,以及使用类属性。这样的话,对于编码和维护带来相当大的便利。在程序进行改动的时候,也只会改动相应的功能就行了,调用的方法是不用改的。更不会一改就改全身。
.反射
① 反射机制 :指在运行状态中,对任意一个类,都能够知道这个类的所有属性和方法;对任意一个对象,都能够调用它的一个方法;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
② 反射API :java通常是先有类再有对象,有对象我就可以调用方法或者属性。反射其实是通过Class对象来调用类里面的方法。通过反射可以调用私有方法和私有属性。大部分框架都是运用反射原理
Class类 :获取到类的属性、方法等信息
Field类 :表示类的属性,通过它获取和设置类中属性的值
Method类 : 表示类的方法,用来获取类中方法的信息,或者执行方法
Constructor类 :表示类的构造方法, 通过它可以动态的创建对象
package Reflect;
/**
* 通过一个对象获得完整的包名和类名
* */
class Demo{
//other codes...
}
class hello{
public static void main(String[] args) {
Demo demo=new Demo();
System.out.println(demo.getClass().getName());
}
}
// 【运行结果】:Reflect.Demo