先抓知识结构主干,再去补充细节
先跟着老师的复习思路走,遇到会的,快速回顾
遇到忘记或者是不会的,先记录,后面自己复习的时候着重回顾
一阶段学习路径:
注意1:开发工具无需纠结,重要的是编程的思路,对于工具而言,选一个自己喜欢的就好,重要的是提高这个自己常用软件的熟练度(快捷键 字体设置 配置JDK…面向百度进行开发)
注意2:一台PC可以安装多个JDK,至于哪个JDK会生效,取决于环境变量配置的是哪个,不建议大家安装最新的版本
注意3:大家在安装的时候,不要选择C盘系统盘,而且路径中不要出现中文或者空格等等其他特殊符号,因为会出现一些未知的问题
JDK(Java Development Kit)
Java开发工具包 ,包含JRE+开发工具,是开发java程序最小的环境
JRE(Java Runtime Environment)
是Java运行时环境,包含JVM+运行java程序所必需的环境,运行java程序最小的环境为JRE
JVM(Java Virtual Machine)
负责加载.class并运行.class文件
注意: .class文件指的是字节码文件,是由.java源文件通过编译生成的文件
所以JVM可以运行字节码文件,我们只需要在不同的OS之上安装对应的JVM,就可以运行同一份java代码,我们把这个现象称为Java的跨平台
就是一个名字,组成元素由字母、数字、下划线、美元符号四种,不能以数字开头,区分大小写,不能使用关键字(true/false/null)作为标识符,见名知意
注意:UpperCamelCase大驼峰命名:每个单词的首字母都要大写,比如类名:HelloWorld
LowerCamelCase小驼峰命名:从第二个单词的首字母才开始大写,比如:
方法名:nextLine()
变量名:deptName
Java中具有特殊意义的全小写单词,一共有50个,其中有2个保留字const goto
单行注释 //
多行注释 /* /
文档注释 /* */,除了注释以外,还可以添加其他信息
变量用于存储一些可能会发生改变的值
格式:
int a = 18; 完成的就是声明+初始化,一步到位
int a; a = 18; 先声明,再赋值
成员变量:
类里方法外,属于类资源
成员变量有自己的默认值,至于值是什么,取决于类型,所以成员变量可以不赋值
成员变量属于类资源,类中全部可以使用,类消失,才会消失
局部变量:
写在方法里/局部代码块中,局部变量没有默认值,必须要进行手动初始化,当局部代码块结束,局部变量也随之释放了
变量的就近原则:如果在一个类中,成员变量与局部变量同名,使用的是局部变量,所以如果想要使用成员变量,需要使用this.变量名用于指定成员变量
口诀:小转大 直接转,大转小 强制转,浮变整 小数没
注意1:boolean类型不参与类型转换
注意2:基本类型能否转换,取决于类型的取值范围,而不是字节数,字节数只能做参考
注意3:我们这里说的是基本类型,引用类型直接的转换与强转取决于是否有继承关系:
你可以说小猫是一只小动物,但你不能说小汽车是一个水果,后面这种就会出现类型转换异常
单分支结构
if(判断条件){符合判断条件后要执行的代码,如果不符合判断条件,就跳过此句,执行后面}
多分支结构
if(判断条件){符合判断条件后要执行的代码,如果不符合判断条件,就跳过此句,执行else中的语句}else{不符合 if 的判断条件,执行的代码,属于其他情况}
嵌套分支结构
if(判断条件1){符合判断条件1后要执行的代码,如果不符合判断条件1,就跳过此句,执行判断条件2}else if(判断条件2){符合判断条件2后要执行的代码,如果不符合判断条件2,就跳过此句,执行判断条件3}else if(判断条件3){符合判断条件3后要执行的代码,如果不符合判断条件3,就跳过此句,执行保底选项}else{保底选项,以上条件均不满足的情况下,执行此处代码【可选项】}
switch(a){case 1 : 操作1;break;【可选】case 2 : 操作2;break;【可选】case 3 : 操作3;break;【可选】case 4 : 操作4;break;【可选】default : 保底选项;【可选】
}
执行顺序:先拿着变量a的值,依次与每个case后的值做比较,如果相等,就执行当前case后的操作,若case后没有break,就绪继续执行下一个case后的操作,如果一直没有遇到break,就会发生穿透的现象,包括default
注意1:小括号中a支持的类型:byte short char int String Integer
注意2:如果配置了default默认选项,而且没有任何case被匹配到,就会执行default后的操作
注意3:case的个数、是否加break、是否加default全是可选的,取决于业务
for(开始条件 ; 循环条件 ; 更改条件){循环体
}
注意1:写法小窍门:从哪开始 到哪结束 循环变量如何变化
注意2:for循环能够执行多少次,取决于循环变量可以取到几个值
嵌套for循环
外层循环控制的是轮数,内层循环控制的是每一轮中执行的次数
对于图形而言,外层循环控制的是行数,内层循环控制的是列数
for(){ //外层循环for(){//内层循环我是一个循环体}
}
高效for循环
for(遍历到的元素的类型 遍历到的元素的名字 :要遍历的数组/集合名){循环体
}
优点:写法简单,效率高
缺点:只能从头到尾的遍历数据,不能进行步长的选择
while循环
使用while通常用来写死循环,但是注意死循环必须要设置出口!!!
while(判断条件){循环体
}
do-while循环
do-while循环一定会执行一次,然后再判断,如果符合条件,再执行后面的循环
do{循环体
}while(判断条件);
循环之间的比较
方法的传值:基本类型传递的是实际值,引用类型传递的是地址
而且方法的参数属于形参,只是格式上需要定义,但是调用方法时起不到限制的作用
形参:定义方法的时候的参数列表
实参:使用方法的时候传入的数据
重写的意义:是在不修改源码的前提下,进行功能的修改和拓展(OCP原则:面向修改关闭,面向拓展开放)
拓展:方法的递归 ,难度较大
权限修饰符的图示
两者都是一种思想,面向过程强调的是过程,凡事亲力亲为,面向对象,强调的是结果,我们是指挥者而不是执行者
Java就是一门面向对象的语言
类是抽象的,类似于设计图纸与模板,指的是一类事物
对象是具体的,是根据设计图纸制作出来一个个独立的实例,拥有自己独立的属性与功能
我们现在可以在类中添加:属性 构造方法 方法 代码块 内部类。。。这些都是可选的,可以根据自己的业务来决定
比如:Phone p = new Phone();对象p的创建过程是:
类与类的关系
继承关系,只支持单继承
比如:class A extends B,A是子类,B是父类,子类具备父类的所有功能
类与接口的关系
实现关系,既可以单实现,也可以多实现
比如:class A implements Inter1{}
比如:class A implements Inter2,Inter3{}
A是实现类,Inter1,Inter2,Inter3是被实现的接口
注意1:实现类去实现接口必须实现接口中的所有抽象方法,如果有任何一个没有实现,就得声明成抽象子类
注意2:创建实现类对象时,一般使用实现类对象,而不是多态对象,因为效果一样
接口与接口的关系
继承关系,既可以单继承,也可以多继承
比如:interface A extends Inter1{}
比如:interface A2 extends Inter2,Inter3{}
A,A2是子接口,Inter1,Inter2,Inter3是被继承的父接口
注意接口A2的实现类需要实现接口A2继承自Inter2和Inter3的所有抽象方法
抽象类与接口的区别
抽象类是一个特殊的类,使用class定义,特殊在这个类中可以定义没有方法体的方法(抽象方法)
接口可以理解成一个特殊的抽象类,特殊在接口中所有的方法都是抽象方法,但注意接口不是类,用interface定义
抽象类中有构造方法,为了给子类创建对象时调用
接口中没有构造方法的,子类调用的是父类的构造方法
接口可以多继承,但抽象类只能单继承
抽象类可以定义普通的成员变量,但接口只能定义静态常量
接口与抽象类均不可以实例化/创建对象
抽象是后天重构的结果,接口是先天设计的结果
/*外部类名.内部类名 对象名 = 外部类对象.内部类对象*/
Outer.Inner oi = new Outer().new Inner();
成员内部类
位置:类里方法外
1)被private修饰
被私有化的内部类在main()中是没有办法直接创建其对象的
可以在私有内部类所处的外部类中,创建一个公共的方法供外界调用,这个方法用来返回创建好的私有内部类对象
2) 被static修饰
静态内部类可以不创建外部类对象,直接创建静态内部类对象,格式:Outer3.Inner3 oi = new Outer3.Inner3();
如果静态内部类中还有静态方法,那么我们可以不创建对象
直接通过链式加载的方式调用:Outer3.Inner3.show2();//表示通过外部类名直接找到静态内部类,再找到静态方法
局部内部类
位置:方法里
直接创建外部类对象,调用局部内部类所处的方法,并不会触发局部内部类的功能
需要在外部类中创建局部内部类的对象并且进行调用局部内部类的功能,才能触发内部类的功能
匿名内部类
位置:可运行代码中,比如 main()中
匿名内部类通常与匿名对象【没有名字的对象】一起使用
格式:new Inter1(){ 我这个大括号其实是一个匿名内部类,我来实现方法 }.eat();
如果只是想使用一次接口/抽象类的某个功能,可以使用匿名内部类
匿名内部类+匿名对象的功能:创建实现类+实现方法+方法功能的一次调用【功能三合一】
try{可能会出现异常的代码
}catch(预测的异常类型 异常的名字){预先设计的,捕获到异常的处理方案
}finally{异常处理结构中一定会被执行到的代码块,常用来关流
}
int hashCode() 返回此字符串的哈希码。
boolean equals(Object anObject) 将此字符串与指定的对象比较,比较的是重写后的串的具体内容
String toString() 返回此对象本身(它已经是一个字符串!)。
int length() 返回此字符串的长度。
String toUpperCase() 所有字符都转换为大写。
String toLowerCase() 所有字符都转换为小写
boolean startsWith(String prefix) 测试此字符串是否以指定的元素开头。
boolean endsWith(String suffix) 测试此字符串是否以指定的字符串结束。
char charAt(int index) 返回指定索引/下标处的 char 值/字符
int indexOf(int ch) 返回指定字符在此字符串中第一次出现处的索引。
int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。
String concat(String str) 将指定字符串连接/拼接到此字符串的结尾,注意:不会改变原串
String[] split(String regex) 根据给定元素来分隔此字符串。
String trim() 返回去除首尾空格的字符串
byte[] getBytes() 把字符串存储到一个新的 byte 数组中
String substring(int beginIndex) 返回一个新子串,从指定下标处开始,包含指定下标
String substring(int beginIndex, int endIndex) 返回一个新子串,从执定下标开始,到结束下标为止,但不包含结束下标
static String valueOf(int i) 把int转成String
String的:
StringBuilder的:
du.api;
/*本类用于测试自动装箱与自动拆箱*/
public class TestNumber2 {public static void main(String[] args) {//1.定义包装类型的数据Integer i1 = new Integer(127);Integer i2 = Integer.valueOf(127);//2.现在的方式:Integer i3 = 5;//不会报错,这个现象就是自动装箱int i4 = i1;//不会报错,这个现象就是自动拆箱}
}
InputStream--抽象父类--不能实例化
FileInputStream--文件字节输入流-FIS
BufferedInputStream--高效字节输入流-BIS
FIS in = new FIS(new File(路径));
FIS in = new FIS(路径);
BIS in = new BIS( new FIS(new File(路径)));
BIS in = new BIS(new FIS(路径));
OutputStream--抽象父类,不能实例化
FileOutputStream--文件字节输出流--FOS
BufferedOutputStream--高效字节输出流-BOS
FOS out = new FOS(new File(路径));
FOS out = new FOS(路径);
BOS out = new BOS(new FOS(new File(路径)));
BOS out = new BOS(new FOS(路径));
Reader--抽象父类--不能实例化
FileReader--文件字符输入流-FR
BufferedReader--高效字符输入流-BR
FR in = new FR(new File(路径));
FR in = new FR(路径);
BR in = new BR(new FR(new File(路径)))
BR in = new BR(new FR(路径));
Writer--抽象父类,不能实例化
FileWriter--文件字符输出流--FW
BufferedWriter--高效字符输出流--BW
FW out = new FW(File/File,append/String pathname/String pathname,append);
BW out = new BW(Writer–所以传的是子类FW(上面那4种));
注意:这里的append参数表示流向文件输出数据的时候是追加还是覆盖,如果不写,默认false是覆盖,如果改为true,表示追加
4. 序列化与反序列化
序列化与反序列化的作用就是对象的保存与传输
序列化:把内存中的对象通过序列化流输出到磁盘中(比如文件里),使用的流是ObjectOutputStream【把数据写出到文件】
反序列化:通过反序列化流将磁盘中的数据恢复成对象,使用的流是ObjectInputStream【把之前写到文件里的数据读到程序中】
注意1:一个类的对象如果想被序列化,那么这个类必须实现可序列化接口
实现这个接口的目的是相当于给这个类做了一个标记,标记可以序列化
注意2:序列化时会自动生成一个UID,表示当前序列化输出的对象的版本信息
反序列化时会拿着当前的UID与之前序列化输出的UID做比较,一致,反序列化成功,不一致,报错
注意3: 所以,标准操作是一次序列化对应一次反序列化
如果目标对象所在的类没有做任何修改,一次序列化也可以对应多次反序列化(根本原因是UID没变)
单个集合的操作:
boolean add(E e) 将指定元素添加到集合中
void clear() 清空集合
boolean contains(Object o) 判断本集合是否包含指定的元素
boolean equals(Object o) 比较集合对象与参数对象o是否相等
int hashCode() 返回本集合的哈希码值
boolean isEmpty() 判断本集合是否为空
boolean remove(Object o) 从本集合中移除指定元素o
int size() 返回本集合中元素的个数
Object[] toArray() 将本集合转为数组
集合间的操作:
boolean addAll(Collection<> c) 将c集合中的所有元素添加到本集合中
boolean containsAll(Collection<> c) 判断本集合是否包含c集合的所有元素
boolean removeAll(Collection<> c) 移除本集合中属于参数集合c的所有元素
boolean retainAll(Collection<> c) 保留本集合与参数集合c的公共元素
集合的迭代:
Iterator iterator() 返回本集合的迭代器
单个集合的操作:
void add(int index, E element) 在集合的指定下标index处插入指定元素element
E get(int index) 返回本集合中指定下标index处的元素
E remove(int index) 移除本集合中指定下标index处的元素
E set(int index, E element) 用参数元素element替换集合中指定下标index处的元素
int indexOf(Object o) 判断指定元素o在本集合中第一次出现的下标,如果不存在,返回-1
int lastIndexOf(Object o) 判断指定元素o在本集合中最后一次出现的下标,如果不存在,返回-1
List subList(int fromIndex, int toIndex) 截取子集合,包含formidex处的元素,不包含toIndex处的元素
集合间的操作与集合的迭代
boolean addAll(int index, Collection<> c) 将参数集合c中的所有元素,插入到本集合中指定的下标index处
ListIterator listIterator() 返回此列表元素的迭代器,这个是List自己的,不太常用,可以逆序迭代
简单方法:
void addFirst(E e) 添加首元素
void addLast(E e) 添加尾元素
E removeFirst() 删除首元素
E removeLast() 删除尾元素
E getFirst() 获取首元素
E getLast() 获取尾元素
E element() 获取首元素
功能一致但是名字不太好记的方法:
boolean offer(E e) 添加尾元素
boolean offerFirst(E e) 添加首元素
boolean offerLast(E e) 添加尾元素
E peek() 获取首元素
E peekFirst() 获取首元素
E peekLast() 获取尾元素
E poll() 返回并移除头元素
E pollFirst() 返回并移除头元素
E pollLast() 返回并移除尾元素
简单方法:
void clear() 清空集合
boolean equals(Object o) 判断集合对象与参数o是否相等
int hashCode() 返回本集合的哈希码值
boolean isEmpty() 判断集合是否为空
int size() 返回本集合中键值对的个数
map单个集合间的操作
boolean containsKey(Object key) 判断map中是否包含指定的key
boolean containsValue(Object value) 判断map中是否包含指定的value
V get(Object key) 根据指定的key返回对应的value,如果不存在,返回null
V remove(Object key) 删除本集合中参数key对应的键值对
V put(K key, V value) 向集合中添加映射关系(键值对)
void putAll(Map<> m) 向本集合中添加m集合的所有映射关系(键值对)
map的迭代
Collection values() 把本map中的Value值取出放入一个Collection中并返回这个Collection
Set keySet() 把本map中的Key值取出放入一个Set集合中并返回这个Set集合
Set<Map.Entry<K,V>> entrySet()
把本map中的每一对KV都看成是一个Entry,把所有的Entry取出放入一个Set集合中并返回这个Set集合
程序:数据与指令的集合,而且程序是静态的
进程:运行中的程序,给程序加入了时间的概念,不同时间进程有不同的状态,进程是动态的,代表OS中正在运行的程序
进程有独立性,动态性,并发性
并行:相对来说资源比较充足,多个CPU同时并发处理多个不同的进程
并发:相对来说资源不太充足,多个资源同时抢占公共资源,比如CPU
线程:线程是OS能够进行运算调度的最小单位
一个进程可以拥有多个线程,当然,也可以只拥有一个线程,只有一个线程的进程称作单线程程序
注意:每个线程也有自己独立的内存空间,当然也有一部分共享区域用来保存共享的数据
线程的几种状态以及线程状态之间的切换
1)新建状态:创建线程对象,申请PCB,对应的是new线程对象
2)就绪状态/可运行状态:万事俱备,只欠CPU,刚刚创建好的线程对象所有资源已经准备好,并且加入到了就绪队列之中
唯有等待操作系统的调度,只要分配了CPU,也就是时间片,当前线程可立即执行,对应的是start()
注意:调用start()并不会立即执行线程对象,这个是由OS的调度规则决定的。我们控制不了
3)执行/运行状态:就绪队列中的线程对象被OS选中,分配了时间片,正在执行
注意:只有就绪状态才能变成运行状态
4)阻塞状态:线程在执行过程中遇到了问题,比如锁阻塞、休眠阻塞、等待阻塞…
注意:我们的阻塞状态,等问题解决了以后/获取了临界资源【要抢占的公共资源】后
是加入到就绪队列中的,转为就绪状态,而不是转为运行状态直接执行
5)终止状态:线程成功执行完毕,释放资源,归还PCB
6)线程的挂起:正在运行中的线程,由于CPU分配的时间片已经用完,所以需要冻结当前线程运行的状态与各项信息
把它插入到就绪队列中,直到下次这个线程被调度执行时,重新恢复现场,继续执行
多线程编程实现方案一:extends Thread继承方式
1)自定义一个多线程类用来继承Thread类
2)重写run()里的业务【这个业务是自定义的】
3)创建线程对象【子类对象】
4)通过刚刚创建好的自定义线程类对象调用start()
注意1:不能调用run(),因为这样调用只会把run()看作一个普通的方法,并不会以多线程的方式启动程序
而且调用start()时,底层JVM会自动调用run(),执行我们自定义的业务
注意2:我们除了可以调用默认的父类无参构造以外,还可以调用Thread(String name),给自定义的线程对象起名字,相当于super(name);
多线程编程实现方案二:implements Runnable 实现方式
1)自定义一个类实现接口Runnable
2) 实现接口中唯一一个抽象方法run()
3) 创建接口实现类的对象,这个对象是作为我们的目标业务对象【因为这个自定义类中包含了我们的业务】
4)创建Thread类线程对象,调用的构造函数是Thread(Runnable target)
5)通过创建好的Thread类线程对象调用start(),以多线程的方式启动同一个业务target
注意1:由于Runnable是一个接口,无法创建对象,所以我们传入的目标业务类,也就是接口实现类的对象
注意2:只有调用start()才能把线程对象加入到就绪队列中,以多线程的方式启动,但是:
接口实现类与接口都没有这个start(),所以我们需要创建Thread类的对象来调用start(),并把接口实现类对象交给Thread(target);
大家可以理解成“抱大腿”,创建的是Thread类的线程对象,我们只需要把业务告诉Thread类的对象就好啦
使用方式二的优势:
1)耦合性不强,没有继承,后续仍然可以继承别的类
2)采用的是实现接口的方式,后续仍然可以实现别的接口
3)可以给所有的线程对象统一业务,业务是保持一致的
4)面向接口编程,有利于我们写出更加优雅的代码
多线程编程实现方案三:Executors 创建线程池的方式
1)创建线程池的工具类wFixedThreadPool(int n);可以创建包含最多n个线程的线程池对象
2)创建好的线程池对象:ExecutorService
使用ute()来讲线程池中的线程以多线程的方式启动,每次调用都会将一个线程对象加入到就绪队列之中
这个线程池对象负责: 新建/启动/关闭线程,而我们主要负责的是自定义的业务
注意:线程池是不关闭的,实现的效果就是线程池中线程对象的随取随用,这样就避免了频繁的创建与销毁线程,不会造成资源浪费
3)合理利用线程池可以拥有的优势:
1. 降低系统的资源消耗:减少系统创建与销毁线程对象的次数,每个线程都可以重复利用,执行多次任务
2. 提高响应速度:当任务到达时,任务可以不用等待线程创建就能立即执行
3. 提高线程的可管理性:可以根据系统的承受能力,调整线程池中线程的数目
防止因为创建多个线程消耗过多的内存导致服务器的崩溃
【每个线程大约需要1MB的内存,线程开的越多,消耗的内存也就越大,最后死机】
多线程数据安全隐患的解决方案
1)出现数据安全问题的原因:多线程程序 + 多个线程拥有共享数据 + 多条语句操作共享数据
2)解决:加锁synchronized同步关键字
1. 同步方法【不太常用】,格式:在方法的定义上加synchronized
2. 同步代码块,格式:
synchronized(唯一的锁对象){可能会出现数据不安全问题的所有代码}
注意1:锁对象必须唯一!!!比如:如果是实现接口的方式,只需要创建一个接口实现类对象。而这个对象当做的是目标业务对象,类中定义的锁对象自然也只有一个比如:如果是继承Thread类的方式,我们需要创建多个子类对象作为线程对象那这个时候不同的线程对象间应该共享同一把锁,所以需要把锁设置为静态,被全局所有对象共享而且建议,此种方式使用的锁对象是本类的字节码对象:类名.class注意2:加锁时,同步代码块的范围需要考虑, 不能太大,太大效率太低;也不能太小,太小锁不住注意3:加锁时,锁对象的类型不做限制,只要保证锁对象唯一即可
同步与异步
异步:是多个线程抢占资源的效果,不排队,所以效率高,但是数据不安全
同步:每次只有一个线程独占资源,排队,所以效率低,但是安全,为了安全必要应该牺牲一部分资源
要求大家掌握的是@Override注解,这个注解可以加在方法上,用来表示这是一个重写的方法
元注解是用来定义其他注解的注解,也就是说,注解的语法与JAVA不同,是靠注解来定义的1. 定义注解的格式:@interface 注解名2. 可以根据元注解对注解进行设置:要求大家掌握的是表示被描述的注解可以使用的位置:值可以多选
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
表示被描述的注解的声明周期:注意值只能3选1
@Retention(RentionPolicy.RUNTIME/SOURCE/CLASS)
1. 我们也可以根据自己的需求来定义个性化的注解使用的是@interface 注解名来定义的,主要使用的就是上面的两个元注解2. 除此之外,我们还可以给注解加功能,比如注解的属性:格式:属性类型 属性名(); 比如:int age();注意:定义了注解的普通属性以后,使用注解时必须给属性赋值,格式:@Rice(age=10)如果给属性设置了默认值,那么使用注解时就不需要给属性赋值了,格式:int age() default 0;3.我们还可以给注解添加特殊的属性value,注意这个属性名字必须是value,类型不作限制注意:特殊属性如果不设置默认值,使用注解时也需要赋值,不过赋值可以简写,比如@Rice("apple")特殊属性赋予默认值后,就可以直接使用注解了,赋予默认值的格式:String value() default "apple";注意:如果有多个属性,并且都没有赋予默认值,那么使用注解时的格式:@Rice(value="apple",age=10)
静态
–需要跳过对象,通过类名直接调用这个返回本类对象的公共方法静态
的–这个对象需要在静态方法中被返回,而静态只能调用静态引用类型变量
【这个变量后续用来保存创建出来的对象的地址值】反射是Java这门语言中比较有特点的一个特征,反射非常强大,我们可以通过反射获取目标类当中的资源,甚至是私有资源
不仅仅如此,我们甚至还可以使用资源,并且创建对象,所以反射是一个经常被使用到的技术
开发过程中,我们有的时候并不能拿到源代码,但是又需要使用资源,那这个时候反射的出现就很有必要了
Class.forName(“类的全路径”); 注意:传入的是类的全路径名,包含包名.类名,而且会抛出异常
类名.class 注意:这个写法需要自己手动接一下获取到的字节码对象,不能用快捷方式的
对象.getClass(); 注意:经常与匿名对象一起使用
获取包名 类名
Package().getName()//包名
SimpleName()//类名
Name()//完整类名
获取成员变量定义信息
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)
获取构造方法定义信息
getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)
获取方法定义信息
getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)
反射新建实例
wInstance();//执行无参构造创建对象
Constructor(int.class,String.class)//要先获取构造方法
wInstance(666,”海绵宝宝”);//再执行含参构造创建对象
反射调用成员变量
DeclaredField(变量名);//获取变量
field.setAccessible(true);//使私有成员允许访问
field.set(实例,值);//为指定实例的变量赋值,静态变量,第一参数给null
(实例);//访问指定实例变量的值,静态变量,第一参数给null
反射调用成员方法
Method m = DeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);//使私有方法允许被调用
m.invoke(实例,参数数据);//让指定实例来执行该方法
如果能够直接操作源码,就不需要使用反射
反射经常用于源码与三大框架底层之中,熟练掌握有助于编程思想的提高
反射的思路与正常使用略有区别,所以需要多练习,掌握这些写法
重点参考笔记中的8个单元测试方法
在java中可以将对象分为两大体系:字节码对象和实例对象
本文发布于:2024-02-02 17:44:20,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170686706445411.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |