Day 23 协议 & 反射

整个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



    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值