整个JavaSE重点部分
面向对象之封装,继承,多态
封装的概念----将一个事物的属性私有化,对外提供公共访问方法,保证数据安全性!
考点:
private的关键字特点:被它修饰的只能在当前类访问
一个标准类的写法:
JavaBean规范(描述事物实体类的写法)
1)属性私有化
2)无参构造方法永远给出
3)setXXX()/getXXX()
继承:
当多个事物有共性内容的时候,抽取出公共内容都独立的类中,这多个类和这个独立
类产生一种关系,"继承关系" ----extends
考点:
1) 子类继承父类,成员变量的问题;成员变量名称一致, 就近原则访问
现在子类的局部位置找,有就使用
然后在子类的成员位置找,有就使用
然后在父类的成员位置找,有就使用
2)构造方法访问呢---------------super:代表父类空间表示(父类对象
的地址值引用)
子类继承父类,不能继承构造方法,但是可以通过super访问父类的构
造方法,子类的所有构造放 "默认访问"父类的无参方法 ;子类的数据可能用到父类的数
据,需要让父类先初始化,肯定要父类的构造方法;
super() ;//访问父类无参
super(xxx):访问父类的有参构造方法
考点3)
this和super的区别?
this.变量名; 访问的本类的成员变量
super.变量名:访问的父类成员变量
this.方法名:访问的本类的成员方法
super.方法名:访问的父类的成员方法
this():访问的本类的无参构造方法
this(xx):访问的本类的有参构造方法
super():访问父类的构造方法
super(xxx):访问的是父类的有参构造方法
4)方法重写和方法重载? (override和overload的区别?)
方法重载:overload:
方法名相同,参数列表不同,与返回值无关
参数列表不同
参数个数不同
参数类型以及参数顺序(考虑类型)
public int xx(int a,double b){}
public int xxx(double a,int b){}
方法重写:
出现继承中,子类继承父类,沿用父类的功能,里面实现的自己的功能;
5)什么情况不能方法重写呢?
当一个方法中被final修饰了不能被重写
final修饰类,类不能继承
final修饰的变量,此时变量是一个常量
多态:
一个事物不同时刻体现的不同形态(内存的变化)
1)多态的前提条件
a)必须有继承关系
b)存在方法重写
c)父类引用指向子类对象
Fu fu = new Zi() ;
2)多态的成员访问特点
成员变量: 编译看左,运行看左
成员方法:编译看左,运行看右,存在方法重写
静态的方法:算不上重写,跟类相关,编译看左,运行看左
构造方法:存在有参以及无参,进行分层初始化
3)多态 的弊端
不能访问子类的特有功能
向下转型
Zi zi = (Zi)fu ;
4)多态的好处----
代码角度(提供代码的扩展性),当方法的形式参数是一个抽象父类---可以传递
子类对象
不管是接口多态/抽象类多态---都是代表的使用的子类对象
常用类
String
转换功能:下去一定看看,总结
获取功能:length()/indexOf()/spilt()--拆分
字符串按照字典顺序比较的方法原理
int compareTo(Object obj)
StringBuffer
两者之间的转换
Date:日期java.util.Date----String文本的相互转换
中间的桥梁 SimpleDateFormat
Date---->String---->格式化 format(Date date):
String---->Date---->解析 parse(String datestr) throws PareseException
Random随机数生成器的 nextInt(int n):0-n的数据,取不到n,获取随机数
System.exit(0):终止jvm
System.gc():手动开启垃圾回收器,会调用Object的finalize(),来回收没有更多引用的
对象
集合
单列集合Collection<E>
List:可重复的,有序
ArrayList:底层数据结构是数组,查询快,增删慢,线程不安全(15倍方
式扩容)
Vector:底层数据结构是数组,查询快,增删慢,线程安全的类
LinkedList:底层数据结构是链表,查询慢,增删快,线程不安全!
Set:不重复的,无序,不能保证迭代次序
HashSet:保证唯一,不能保证爹次序
TreeSet:针对集合排序:根据条件排序
遍历集合------------------>增强for来替代迭代器
for(泛型的数据类型 遍历名 :集合对象){
}
使用变量名即可!
双列集合Map<K,V>
HashMap<K,V>--->K必须唯一,如果键存储的自定义类型,要重写Object的equas
和hashCode
TreeMap<K,V>:
底层:红黑树结构
键必须唯一,如果存自定义类型,按照什么主要条件:排序,
自己分析次要条件
Map的集合遍历方式
1)keySet()--->获取所有的键,通过键获取值
2)entrySet()--->获取所有的键值对对象,通过键值对对象,获取键和获取值
多线程
1)线程的创建方式有几种
三种
1)继承
2)实现Runnable----静态代理(重点)
3)线程池(重点)
什么静态代理:代理就是和真实角色都需要实现同一个接口
2) 线程的生命周期---状态几种
6种--内部枚举
NEW
RUNNABLE
BLOCKED
WAITTING
TEIMED_WAITTING
TERMINATED
3) 解决线程安全问题----------->synchronzied同步代码块
synchronized(锁对象){
将多条语句对象共享数据的操作包起来
}
//锁对象:可以是任意Java类对象,包含Object以及自定义的
或者是同步方法---->锁对象this:代表当前类对象地址值引用
public 返回值类型 synchronzied 方法名(形式参数列表){
...
}
或者是静态同步方法---->锁对象 :字节码文件对象 类名.class属性
public 返回值类型 synchronzied 方法名(形式参数列表){
...
}
4)等待唤醒机制--------->信号灯法解决死锁问题
生产者和消费者模式思想
循序渐进的展示数据
A线程---生产者
没有数据的时候,等待产生数据,有数据了,修改标记,唤醒B线程,使用数据
B线程---消费者
有数据,等待消费数据,没有数据了,修改标记,唤醒A线程,产生数据
一旦A线程,B线程就要使用数据
依次展示数据效果 不断循环--->A产生一次数据-----B使用(输出)一次数
据
在里面使用同步代码块+锁对象调用wait()和notify方法()
5)为什么 wait()和notify方法()在Object中定义呢?
因为锁对象可以是任意Java类对象,规定在Object类中,可以说wait的特点,调用的时候
立即释放锁,才能唤醒对方线程...
6)线程池
7大参数
Executors里面的
public static ExceutorService newFixedThreadPool(int nThreads) //2条
件线程
返回值ExceutorService 接口----实现类 ThreadPoolExecutor :规定了线程池
的参数
1)核心线程数量
//volatile 关键字: 和synchronized 语义上都是解决同步安全的
private volatile int corePoolSize;
2)最大线程数量
private volatile int maximumPoolSize;
3) 线程工厂 是一个接口
private volatile ThreadFactory threadFactory;
作用给线程池中创建线程的
ThreadFactory-->里面的子实现类DefaultThreadFactory实现了
public Thread newThread(Runnable r) {
//创建线程
Thread t = new Thread(xxxx) ;
}
4)线程池的拒绝策略
private volatile RejectedExecutionHandler handler;
当线程池中的线程数量已经达到最大了,创建线程不不能放在线程池中,线程池
的这个参数是启用拒绝策略
5)工作队列(阻塞队列):当一个线程被使用的时候,其他线程在队列中等待另一
个用户操作这个线程,本身就是集合,集合可以存储很多的线程对象
private final BlockingQueue<Runnable> workQueue;
6)当超过最大线程数量,线程池的存活时间 耗时间的计量单位
private volatile long keepAliveTime; -
7) 是否允许最大线程的超时等待
private volatile boolean allowCoreThreadTimeOut;
IO流
字符流针对文本文件读写复制
FileReader
FileWriter 他们可以直接操作文件
BufferedReader readLine()
BufferedWriter newLine()
字节流
BufferedInputStream 和BufferedOutputStream一次读取一个字节数组
Properties (属性集合列表)
/**
* @author liutao
* @date 2022/8/27 9:46
*
* Properties类表示一组持久的属性。 ----称为"属性集合列表"
* Properties可以保存到流中或从流中加载。---->等会说下跟流相关的功能
* 属性列表中的每个键及其对应的值都是一个字符串。---->所有后期都使用这个属性集合类读取
* 后缀名.properties的配置文件(属性配置文件)
* (必须在src下面创建,类路径下)
*
* 传统的配置:xx.txt文件(普通文本文件)
*
*
* java.util.Properties没有泛型--->继承Hashtable<K,V>------------------->最终实现接口Map<K,V>
* 构造方法:Properties() :创建空的属性列表
* 能够使用Map的功能
* put(K k,V v):添加键值对
* Set <K> keySet():获取所有的键的集合
* V get(K k) :通过键获取值
*/
public class PropertiesDemo {
public static void main(String[] args) {
//创建一个集合属性列表,使用Map的功能完成添加,以及遍历
//构造方法:Properties() :创建空的属性列表
Properties prop = new Properties() ;
System.out.println(prop);
//Map的功能
prop.put("高圆圆","30") ;
prop.put("赵又廷","35") ;
prop.put("张杨","32") ;
prop.put("张三丰","60") ;
System.out.println(prop);
//遍历
//获取所有的键的集合
Set<Object> set = prop.keySet();
for(Object key :set){
//通过键获取值
Object value = prop.get(key);
System.out.println(key+"="+value);
}
}
}
/**
* @author liutao
* @date 2022/8/27 10:24
* Properties自己的添加键值对(字符串的键和值),以及自己的遍历功能,
* 自己的通过键获取值的功能 (推荐都是使用特有方式)
* public Object setProperty(String key,String value):添加键和值的方法
* public Set<String> stringPropertyNames():获取属性列表中的所有的键
* public String getProperty(String key):属性列表中通过键获取值
*/
public class PropertiesDemo2 {
public static void main(String[] args) {
//创建一个属性列表
Properties prop = new Properties() ;
System.out.println(prop);
//public Object setProperty(String key,String value):添加键和值的方法
prop.setProperty("高圆圆","30") ;
prop.setProperty("赵又廷","30") ;
prop.setProperty("高圆圆","35") ;
prop.setProperty("文章","25") ;
prop.setProperty("马伊琍","34") ;
System.out.println(prop);
System.out.println("--------------------------------------");
//public Set<String> stringPropertyNames():获取属性列表中的所有的键
Set<String> keySet = prop.stringPropertyNames();
for(String key:keySet){
//public String getProperty(String key):属性列表中通过键获取值
String value = prop.getProperty(key);
System.out.println(key+""+value);
}
}
}
/**
* @author 刘涛
* @date 2022/8/27 10:33
*
* 需求:
* 1)将属性集合列表中的内容,保存到当前项目下的name.txt文件中
* Propreties提供一些功能:
* 保存:将属性列表中的内容保存到流中---输出流可以输出文件...
* 字节输出流 属性列表的描述
* public void store(OutputStream out,String comments) throws IOException
* 字符输出流 属性列表的描述
* public void store(Writer out,String comments) throws IOException(推荐)
* 文本文件:使用记事本打开读的的懂,使用字符流
*
* 2)要将当期项目下的2208.txt文件内容加载到属性集合列表中
*
* 将指定文件的内容加载到属性集合列表汇总
* public void load(Reader reader) throws IOException(推荐)
* public void load(InputStream in) throws IOException
*
*/
public class ProptiesDemo3 {
public static void main(String[] args) throws Exception {
//调用方法
//myStore() ;
myLoad() ;
}
//要将当期项目下的2208.txt文件内容加载到属性集合列表中
private static void myLoad() throws Exception {
//创建Properties属性集合列表
Properties properties = new Properties() ;
System.out.println(properties) ;
Reader r = new FileReader("2208.txt") ;
// public void load(Reader reader) throws IOException(推荐)
//public void load(InputStream in) throws IOException
properties.load(r);
System.out.println(properties);
System.out.println("加载成功");
r.close();
}
//将属性集合列表中的内容,保存到当前项目下的name.txt文件中
private static void myStore() throws Exception {
//创建属性集合列表
Properties prop = new Properties() ;
//添加一些属性内容
prop.setProperty("张三","30") ;
prop.setProperty("李四","40") ;
prop.setProperty("王五","35") ;
// public void store(Writer out,String comments) throws IOException(推荐)
prop.store(new FileWriter("name.txt"),"name's list");
}
}
Udp协议
/**
* @author liutao
* @date 2022/8/29 10:48
* UDP接收端代码实现
*
* 1)创建接收端的Socket对象
* 2)创建一个接收容器(数据报包DatagramPacket)(字节数组长度1024个长度或者它的整数倍),自定义字节缓冲区,将数据报包放进去
* 3)接收端的socket对象,接收数据报包
* 4)解析接收容器中的真实的缓冲区的字节数组以及实际长度---->转换成字符串(发送端实际发来的内容)
* 5)展示发送的ip地址以及发送的内容,,,表示 "某个发送发送的数据是什么..."
*
*
* 先开启接收端,接收端不能开多个,因为一个端口只能只能绑定一次,所以会出现BindException:绑定一次
* 端口号被占用 (address alread in use)
*/
public class UDPReceiver {
public static void main(String[] args) throws Exception {
// 1)创建接收端的Socket对象,指定绑定的端口号
//public DatagramSocket(int port) throws SocketException
DatagramSocket ds = new DatagramSocket(10086) ;
//2)创建一个接收容器(数据报包DatagramPacket)(字节数组长度1024个长度或者它的整数倍)
// 自定义字节缓冲区,将数据报包放进去
//public DatagramPacket(byte[] buf, 参数1:用于保存传入数据报的缓冲区。
//int length) 参数2:要读取的字节数。
byte[] bytes = new byte[1024] ;
int length = bytes.length ;
DatagramPacket dp = new DatagramPacket(bytes,length) ;
//3)接收端的socket对象,接收数据报包
//底层会将的发送端的内容填充到这个数据报包的缓冲区中
//public void receive(DatagramPacket p) throws IOException
ds.receive(dp);
//4)填充进去之后,从数据报包的缓冲区中解析实际的内容
//public byte[] getData():获取缓冲区中真实的字节数组
//public int getLength():返回接收的真实字节数 的长度
byte[] bytes2 = dp.getData();
int length2 = dp.getLength();
//转换成字符串
String receiverStr = new String(bytes2,0,length2) ;//从0开始解析真实内容
//5)展示ip地址(发送端的)以及现在接收的内容
//数据报包---public InetAddress getAddress() 获取ip地址对象
//InetAddress ---->String getHostAddress() ip地址字符串
String ip = dp.getAddress().getHostAddress();
System.out.println("data is--->"+receiverStr+",data from---->:"+ip);
//接收端释放资源
ds.close(); //在真实场景中,接收端不关闭的
}
}
/**
* @author liutao
* @date 2022/8/29 10:32
*
* Udp协议 ---->数据包的形式发送 (发送和接收端的数据传输)
* 发送端的代码步骤
* 1)创建发送端的Socket对象
* 2)创建数据报包对象
* 3)使用发送的端的socket对象调用发送方法发送数据报包
* 4)释放资源
*
*/
public class UDPSend {
public static void main(String[] args) throws Exception {
/**
* 1)创建发送端的Socket对象
* 2)创建数据报包对象
* 3)使用发送的端的socket对象调用发送方法发送数据报包
* 4)释放资源
*/
//1)创建Udp协议发送端的Socket对象
//DatagramSocket 用于发送和接收数据报数据包的套接字
//public DatagramSocket()throws SocketException
DatagramSocket ds = new DatagramSocket() ;
//2)创建数据报包对象
//DatagramPacket:数据报包,用于udp里面数据传输
//public DatagramPacket(byte[] buf, 用于发送的数据---字符串---转换成字节数组
// int length, 数据长度
//InetAddress address, ip地址对象
// int port) 端口号
//参数1:字节数组
//byte[] bytes = "hello,UDP我来了".getBytes() ;
//参数2:字节数组长度
// int length = bytes.length ;
//参数3:ip地址对象
// InetAddress inetAddress = InetAddress.getByName("192.168.1.5");
//参数4:端口号 0-65535 0-1024保留端口
// int port = 10086 ;
//一步走
DatagramPacket dp = new DatagramPacket(
"hello,UDP我来了".getBytes(),
"hello,UDP我来了".getBytes().length,
InetAddress.getByName("192.168.1.5"),
10086) ;
//3)使用发送的端的socket对象调用发送方法发送数据报包
//public void send(DatagramPacket p) throws IOException:发送端的socket对象发送数据报包
ds.send(dp);
//4)释放资源
ds.close() ;
}
}
Tcp协议
/**
* @author 刘涛
* @date 2022/8/29 14:13
*
* TCP协议方式, 客户端和服务器端的传输
*
* 客户端要发送的数据的步骤
* 1)创建TCP协议 客户端的Socket对象,指定ip地址以及端口
* 2)从客户端所在的通道获取的字节数出流对象
* 3)写数据过去
* 4)关闭客户端资源
*/
public class TcpClient {
public static void main(String[] args) throws Exception {
// 1)创建TCP协议 客户端的Socket对象,指定ip地址以及端口
//public Socket(String host,int port)throws UnknownHostException,IOException
//参数1:指定的ip地址或者主机名 参数2:端口号 0-65535(0-1024属于保留端口)
Socket socket = new Socket("192.168.1.5",8888) ;
//2)从客户端所在的通道获取的字节数出流对象
//Socket--->成员方法:
//public OutputStream getOutputStream() throws IOException
OutputStream out = socket.getOutputStream();
//3)写数据过去
out.write("hello,TCP,我来了".getBytes());
//4)关闭客户端资源
socket.close();
}
}
/**
* @author liutao
* @date 2022/8/29 14:33
* TCP服务器端步骤
*
* 1)创建服务器端的Socket对象
* 2)监听客户端连接----阻塞式方法,只要客户端绑定端口和服务器端不一致,不会建立连接
* 一旦一致,会建立连接通道,获取连接的通道的Socket(客户端对象)
* 3)获取监听到的客户端Socket的通道内的字节输入流
* 4)读数据 :一次读取一个字节数组
* 5)展示数据
*
* 先运行服务器端,监听客户端连接,在运行客户端
*/
public class TcpServer {
public static void main(String[] args) throws Exception {
System.out.println("服务器正在监听...");
//1)创建服务器端的Socket对象 ServerSocket
// public ServerSocket(int port)throws IOException
ServerSocket ss = new ServerSocket(8888) ;
//2)监听客户端连接----阻塞式方法,只要客户端绑定端口和服务器端不一致,不会建立连接
// 一旦一致,会建立连接通道,获取连接的通道的Socket(客户端对象)
//public Socket accept() throws IOException
Socket s = ss.accept();
System.out.println("服务器监听到客户端了....建立通道");
//3)获取2)中的客户端的所在的通道内的字节输入流
//public InputStream getInputStream() throws IOException
InputStream inputStream = s.getInputStream();
//4) 读数据 :一次读取一个字节数组
//自定义缓冲区
byte[] bytes = new byte[1024] ;
int len = inputStream.read(bytes);
//转换成String
String str = new String(bytes,0,len) ; //从0开始读取实际字节数--->String
//获取ip地址
//Socket客户端类中---->public InetAddress getInetAddress()
String ip = s.getInetAddress().getHostAddress();
// 5)展示数据
System.out.println("data is---->"+str+",date from-->:"+ip);
//释放资源 :服务器端(真实场景不需要关闭)
ss.close();
}
}
**
/**
* @author 刘涛
* @date 2022/8/29 16:27
* 客户端不端的键盘录入数据,服务器端将这数据接收到之后,将数据输出到指定的文件(服务器端输出文件---.txt文件)
*
*
* 分析:
* 1)客户端BufferedReader 字符输入流---键盘录入数据
* 2)将录入的数据-----通过通道内输出写----到服务器端
* 客户端对象.getOutputStream()---->OutputStream ----->封装BufferedWriter
* BufferedWriter(Writer out)---->
* BufferedWriter(new OutputStreamStreamWriter(OutputStream out))
* BufferedWriter(new OutputStreamStreamWriter(客户端对象.getOutputStream()))
*
*
*
* 3)服务器端--监听客户端---------->获取通道内getInputStream---->InputStream---->封装BufferedReader
* ---一次读取一行
* BufferedReader(Reader in)--->
* BufferedReader(new InputStreamReader(InputSteram in))
* BufferedReader(new InputStreamReader(监听到客户端对象.getInputStream())) ;
*
*
*
* 4)在服务器端创建BufferedWriter:字符缓冲输出流, BufferedWriter(new FileWriter("a.txt")) ;
* 使用通道的内封装的字符缓冲输入流一次读取一行,
* 使用这个BufferedWriter(new FileWriter("a.txt")) ; 给文件写一行
*
* 最终看文件的内容....
*
*
*
*
*/
public class ClientTest2 {
public static void main(String[] args) throws Exception{
//客户端不端的键盘录入数据,
//创建客户端的socket对象
Socket socket = new Socket("192.168.1.5",12345) ;
//使用BufferedReader字符缓冲输入 流的特有功能readLine()可以读取一行,键盘录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
//获取通道内的字节输出流,写数据
// OutputStream outputStream = socket.getOutputStream();
// 封装通道内的字节输出流---->将转换字符缓冲输出流
BufferedWriter bw = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream())) ;
//提示
System.out.println("请您输入数据:");
String line = null ;
while((line=br.readLine())!=null){
//自定义结束条件
if("886".equals(line)){
break;
}
//给封装通道内的字符缓冲输流写入一行 写到通道内的输出流对象中
bw.write(line) ;
bw.newLine(); //换行
bw.flush(); //刷新
}
//释放资源
socket.close();
}
}
/**
* @author liutao
* @date 2022/8/29 16:41
* 服务器端将这数据接收到之后,将数据输出到指定的文件(服务器端输出文件---.txt
*/
public class ServerTest2 {
public static void main(String[] args) throws Exception{
System.out.println("等待客户端连接...");
//创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(12345) ;
//监听客户端连接
Socket s = ss.accept();
System.out.println("客户端已连接...");
//获取监听客户端的通道输入流
//InputStream inputStream = s.getInputStream();
//封装----->字符缓冲输入流
// BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)) ;
BufferedReader br = new BufferedReader(
new InputStreamReader(s.getInputStream())) ;
//创建BufferedWriter 给当前项目下 输出a.txt文件
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt")) ;
//不断从通道内的输入流读一行,给bw流中写一行,输出到a.txt文件中
String line = null ;
while((line=br.readLine())!=null){
bw.write(line) ;
bw.newLine();
bw.flush();
}
//释放资源
bw.close(); //指向文件的流对象
ss.close();//服务器端关闭
}
}
udp&tcp 的区别
1)是否建立连接通道
UDP:不可靠连接,不需要建立连接通道
TCP:可靠连接,需要建立连接通道的
2)是否安全
UDP,线程不安全的,效率高
TCP,线程安全,需要建立通道(三次握手),效率低(需要等待服务器端监听客户端连
接)
3)发送数据大小是否有限制
UDP,不适合发送大数据,限制的大小64kb
TCP,适合发送大数据相对udp来说
4)从代码角度考虑;都是socket对象,区别?
UDP:DatagramSocket—>通过数据包的形式,将ip地址以及端口绑定,(是在数
据包中)
是一数据包的填充方式—>接收端接收
TCP:Socket和ServerSocket—>客户端Socket就指定了端口以及主机的ip地址
是一种字节流的方式写和读
给面试官说下 TCP三次握手
反射
/**
* @author 刘涛
* @date 2022/8/30 12:00
*/
//定义一个Person类
public class Person { //class 包名.类名 字节码文件
public String name ; //姓名
private int age ; //私有的年龄
private String gender ; //默认修饰的性别
//无参构造
public Person(){}
//私有修饰的带两个参数的构造方法
private Person(String name,int age){
this.name= name ;
this.age = age ;
}
//默认修饰符的带三个参数的构造方法
Person(String name,int age,String gender){
this.name = name ;
this.age = age ;
this.gender = gender ;
}
//成员方法
//带参,没有返回值
public void show(String s){
System.out.println(s) ;
}
//带参,有返回值
private String myFunction(int number){
return "helloworld"+number ;
}
//不带参,没有返回值的
void myMethod(){
System.out.println("myMethod...");
}
//不带参,有返回值的
protected String function2(){
return "hello,JavaEE" ;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
/**
* @author 刘涛
* @date 2022/8/30 11:56
*
* 反射思想:
* 通过类加载器---校验语法以及类的初始化,获取类的字节码文件对象
* 通过字节码文件对象
* 获取这个类的构造器的类Constructor,创建类实例
* 获取这个类的成员方法所在Method类,调用成员方法
* 获取这个类的成员变量Field,可以给成员变量(类中方法外)
*
* 面试题:获取字节码文件对象有几种方式? Class--->正在运行的Java类对象
* 3种
* 1)Object类的getClass()方法 :任意Java类对象的.getClass()--->Class
* 2)任意Java类型的.class属性 类名.class------->Class
*
* 3)方式3:
* Class:就是代表字节码文件对象(正在运行的java应用程序的类或者接口)
*
*
* 静态的方法:直接获取当前类的字节码文件对象(称为 Class类对象)
* public static Class<?> forName(String className)
* throws ClassNotFoundException 在开发中常用的
* 因为参数为String类型,经常用在配置文件 src下面的xxx.properties属性配置文件
* 参数:必须是当前类的"全限定名称" 包名.类名
* com.qf.reflect_01
* class Person{}
*
* com.qf.reflect_02
* class Person{}
*
* Class.forName("Person") ;错误的
*/
public class PersonDemo {
public static void main(String[] args) throws Exception {
//创建Person类对象
Person p = new Person() ;
Class c = p.getClass();
System.out.println(c);//class com.qf.reflect_04.Person
System.out.println("----------------------------------");
Class c2 = Person.class ;
System.out.println(c2);//lass com.qf.reflect_04.Person
System.out.println(c==c2); //true
System.out.println("-----------------------------------");
//public static Class<?> forName(String className) throws ClassNotFoundException
//Class c3 = Class.forName("Person") ;//ClassNotFoundException:没有指定全限定名称,一定要有包名
Class c3 = Class.forName("com.qf.reflect_04.Person") ;
System.out.println(c3) ;
}
}
/**
* @author liutao
* @date 2022/8/30 14:33
* 通过字节码文件对象 获取这个类的构造器的类Constructor,创建类实例 (重点)
*
* 之前写代码---无参构造方法
* Person p = new Person() ;
* System.out.println(p) ; //执行重写toString(),打印出成员信息表达式
*
*
*
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
//1)现在反射的方式获取类的字节码文件对象 Person类
Class c = Class.forName("com.qf.reflect_04.Person") ;
System.out.println(c);//class com.qf.reflect_04.Person
// 获取这个类的所有的构造方法
//public Constructor<?>[] getConstructors(): 获取这个类字节码文件对象中所有公共构造的方法
//public Constructor<?>[] getDeclaredConstructors():获取所有的构造方法,包括私有等等
// Constructor[] constructors = c.getConstructors();
// Constructor[] constructors = c.getDeclaredConstructors() ;
// for(Constructor con:constructors){
//System.out.println(con);//public com.qf.reflect_04.Person()
// System.out.println(con);
/**
* com.qf.reflect_04.Person(java.lang.String,int,java.lang.String)
* private com.qf.reflect_04.Person(java.lang.String,int)
* public com.qf.reflect_04.Person()
*/
// }
//2)获取指定的公共的构造器对象
//参数:可变参数: 如果有参数,必须写上参数类型的class属性,没有参数,写null,忽略不写!
//假设--->构造方法的带了一个String类型参数---->String.class
//public Constructor<T> getConstructor(Class<?>... parameterTypes)
// System.out.println(String.class);
Constructor con = c.getConstructor(); //获取到了Person类的无参构造器方法
// System.out.println(con);//public com.qf.reflect_04.Person()
//Constructor类:代表的构造器方法---->
//public T newInstance(Object... initargs):通过构造器创建当前类实例
//参数:为调用构造函数的传递参数,没有参数不用传递,
//返回值:代表就是当前类的实例---->默认就执行toString
Object obj = con.newInstance(); //相当于 类名对象名 = new 类名() ; obj---就是那个对象名
System.out.println(obj);
System.out.println("----------------------------------");
Person p = new Person() ;
System.out.println(p) ; //执行重写toString(),打印出成员信息表达式
System.out.println("----------------------通过反射创建当前类对象,获取私有的构造方法并且给成员变量赋值-------------------------");
//创建对象:有参构造方法
// Person p2 = new Person("高圆圆",20) ; //前提示构造方法可以访问的,不是私有的,现在它是私有---->
// 只能通过反射
//System.out.println(p2) ;Person{name='高圆圆', age=20, gender='null'}
//通过当前字节码文件对象获这个类的私有的带两个参数的构造方法
//public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):
//获取指定的构造方法,如果这个构造方法带参数,一定要参数类型的.class---获取参数类型的字节码文件对象
Constructor con2 = c.getDeclaredConstructor(String.class,int.class) ; //形式参数
System.out.println(con2);
//创建类对象---就相当于上面的p2
//public T newInstance(Object... initargs):通过构造器创建当前类实例
//参数:为调用构造函数的传递参数,没有参数不用传递, 有参数,传递实际参数,参数类型要和构造方法的形式参数匹配
//返回值:代表就是当前类的实例---->默认就执行toString
//Constructor构造器对象中继承了AccessibleObject有一个方法:
//public void setAccessible(boolean flag):参数为true,取消Java语言访问检查,私有可以访问 (反射的暴力访问)
con2.setAccessible(true);
Object obj2 = con2.newInstance("高圆圆",20) ;//IllegalAccessException:非法访问异常:这个构造方法私有
System.out.println(obj2);
System.out.println("-------------------通过反射获取默认修饰带三个参数的构造方法------------------------");
//之前的写法--->默认修饰符:可以在同一个包下,不同包下就不能访问了
// Person p3 = new Person("高圆圆",43,"女") ;
//System.out.println(p3);
//反射的方式
//通过当前类的字节码文件对象获取指定的构造方法的Constructor类对象
Constructor con3= c.getDeclaredConstructor(String.class,int.class,String.class) ;
//取消java语言访问检查
con3.setAccessible(true);
//创建当前类实例
Object obj3 = con3.newInstance("高圆圆",43,"女") ;
System.out.println(obj3); //就想于上面的p3
}
}