【java核心技术ΙΙ】总复习

目录

异常

Throwable的成员方法

try...catch

finally(try...catch..finally...)

throws

throws和throw的区别

自定义异常 

 举例(应用自定义异常+try...catch+throws+throw)

 异常注意事项

File类

构造方法

成员方法

实例:遍历目录

IO流 

分类

按照数据流向

按照数据类型

常用基类

字节输出流 OutputStream

FileOutputStream 

字节流写数据的方式

字节输入流 InputStream

FileInputStream

字节流读数据的方式

字节缓冲流

字节缓冲输出流 BufferedOutputStream

字节缓冲输入流 BufferedInputStream

字符流

OutputStreamWriter 字符输出流

InputStreamReader 字符输入流

操作基本数据类型的流

DataInputStream

DataOutputStream 

内存操作流

操作字节数组

操作字符数组

操作字符串

打印流

字节流打印流

字符打印流

标准输入输出流

随机访问流RandomAccessFile

合并流SequenceInputStream

序列化流

序列化流 ObjectOutputStream

反序列化流 ObjectInputStream

Properties集合

Properties作为Map集合的使用

NIO包下的IO流

多线程

Thread类的基本获取和设置方法

多线程的实现

继承Thread类

实现Runnable接口

实现Callable接口(略)

run()方法和start()方法的区别?

匿名内部类方式使用多线程

线程调度

如何设置和获取线程优先级

线程控制

线程的生命周期图

线程安全问题

同步代码块

同步方法

为什么wait(),notify(),notifyAll()定义在Object类中而不是Thread类? 

sleep()方法和wait()方法的区别?

Lock锁

死锁问题

线程间通信

 生产者消费者问题

线程的状态转换图

线程组

线程池

定时器

Timer

TimerTask

网络编程

UDP通信原理

TCP通信原理

反射

获取class对象

1.使用类的class属性来获取该类对应的class对象

2.调用对象的getClass()方法,返回该对象所属类对应的Class对象

3.使用该Class类中的静态方法forName(String className)

获取类名

获取构造方法并使用

Constructor类中用于调用构造方法的方法

获取成员方法并使用

Method类中用于调用成员方法的方法

获取成员变量并使用

Field类中用于给成员变量赋值的方法

JDBC编程

JDBC核心类

JDBC连接数据库

GUI

菜单组件


异常

异常就是Java程序在运行过程中出现的错误。

Java中的异常被分为两大类:编译时异常和运行时异常。所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常就是编译时异常 编译时异常 Java程序必须显式处理,否则程序就会发生错误,无法通过编译 运行时异常 无需显示处理,也可以和编译时异常一样处理

Throwable的成员方法

public void printStackTrace() 把异常的错误信息输出在控制台
public String toString() 返回此抛出的简短描述  
public String getMessage() 返回throwable的详细消息字符串

try...catch

格式:try{可能出现异常的代码;}catch(变量名 异常名) {异常的处理代码;}

package 异常;


public class Yichang {
	
	public static void main(String[] args) {
		try { 
		int[] arr= {1,2,3};
		System.out.println(arr[3]);}
/*Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
  at 异常.Yichang.main(Yichang.java:9)*/
        catch(ArrayIndexOutOfBoundsException a) {
        	System.out.println("存在错误!");
//public void printStackTrace() 把异常的错误信息输出在控制台
//public String toString() 返回此抛出的简短描述  
//public String getMessage() 返回throwable的详细消息字符串
        	//a.printStackTrace();
/*存在错误!
java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
	at 异常.Yichang.main(Yichang.java:9)*/
        	System.out.println(a.toString());
        	//java.lang.ArrayIndexOutOfBoundsException: Index 3 out of bounds for length 3
        	System.out.println(a.getMessage());
        	//Index 3 out of bounds for length 3
        }
		
	}

}

finally(try...catch..finally...)

被finally控制的语句体一定会执行

特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))

作用 用于释放资源,在IO流操作和数据库操作中会见到

finally语句与return语句的执行顺序也要注意,可以参考下面:

finally语句与return语句详解_星光_依旧灿烂的博客-CSDN博客_finally和return

throws

格式:throws 异常类名;【跟在方法的括号后面】

public static void method() throws ArrayIndexOutOfBoundsException{
		int[] arr= {1,2,3};
		System.out.println(arr[3]);
	}

throws和throw的区别

throwsthrow
用在方法声明后面,跟的是异常类名用在方法体内,跟的是异常对象名
表示抛出异常,由该方法调用者来处理表示抛出异常,由方法体内的语句来处理
表示抛出异常的一种可能性,并不一定会发生这些异常执行throw一定抛出了某种异常

自定义异常 

继承自Exception类

格式: 

public class 异常类名 extends Exception{

  无参构造

  带参构造

}

public class Zidingyi extends Exception {
	/*
	 * 报错: serializable 类 Zidingyi 未声明类型为 long 的静态终态 serialVersionUID 字段
	 */
	private static final long serialVersionUID = -5068192539448251924L;

	public Zidingyi() {}
	public Zidingyi(String message) {
		super(message);
	}

}

 举例(应用自定义异常+try...catch+throws+throw)

package 异常;

public class Zidingyi extends Exception {
	/*
	 * 报错: serializable 类 Zidingyi 未声明类型为 long 的静态终态 serialVersionUID 字段
	 */
	private static final long serialVersionUID = -5068192539448251924L;

	public Zidingyi() {}
	public Zidingyi(String message) {
		super(message);
	}

	public static void check(int score) throws Zidingyi{
		if(score<0||score>100) {
			throw new Zidingyi();
		}else {System.out.println("分数正常");}
	}
	
	public static void main(String[] args) {
		try {
			check(-111);
		} catch (Zidingyi e) {
			e.printStackTrace();
		}
		/*try {
			check(1);
		} catch (Zidingyi e) {
			e.printStackTrace();
		}*/
	}
}

 异常注意事项

子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏,儿子不能比父亲更坏)

如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常

如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws

       

File类

文件和目录路径名的抽象表示形式

构造方法

public File(String pathname)

public File(String parent,String child)

public File(File parent,String child) 

成员方法

创建功能

public boolean createNewFile()

public boolean mkdir()

public boolean mkdirs()

删除功能

public boolean delete()

重命名功能

public boolean renameTo(File dest)

判断功能

public boolean isDirectory()

public boolean isFile()

public boolean exists()

public boolean canRead()

public boolean canWrite()

public boolean isHidden()

基本获取功能

public String getAbsolutePath()

public String getPath()

public String getName()

public long length()

public long lastModified()

高级获取功能

public String[] list()

public File[] listFiles()

【java】文件输出流 与 文件输入流 实例_老坛酸菜吃鸭子的博客-CSDN博客_java文件输入输出流实例

实例:遍历目录

package IO;
import java.io.File;
public class Traverfile {
	
	public static void main(String[] args) {
		File f=new File("D://school"); //给定路径
       //若要查找输入路径,可以增加scanner对象实现
		allfile(f);//遍历方法
	}
	
	public static void allfile(File f) {
		File[] fileArrays=f.listFiles();//创建Filie数组存储目录内容
		if(fileArrays!=null) {//如果目录数组非空
			
		for(File i:fileArrays) {//使用增强for循环遍历
			
			if(i.isDirectory())//如果是目录
				allfile(i);//则递归调用
			else//不是目录(即文件)
			System.out.println(i.getAbsolutePath());//则打印绝对路径
			
		}
		
		}
	}
 
}
 
/*输出结果:
D:\school\(中)学生-课程-选课_Data.MDF
D:\school\(中)学生-课程-选课_Log.LDF
D:\school\100列.sql
D:\school\97列.sql
D:\school\SCHOOL\SCHOOLDATABASE.mdf
D:\school\SCHOOL\SCHOOLDATABASE_log.ldf
D:\school\school.bak
D:\school\school20170228
D:\school\school_Data.MDF
D:\school\school_Log.LDF
D:\school\xueshengxunke.bak
D:\school\可重复的前三名.sql
D:\school\数据导出.mdb
D:\school\数据导出.xlsx
*/
 
//递归,把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解(主要找到递归出口与递归规则)
//思考一下这个实例的递归出口与递归规则是什么

IO流 

IO流用来处理设备之间的数据传输 (上传文件和下载文件)

Java对数据的操作是通过流的方式

Java用于操作流的对象都在IO包中 

分类

按照数据流向

输入流    读入数据

输出流    写出数据

按照数据类型

字节流 字符流

什么情况下使用哪种流呢?

如果数据所在的文件通过windows自带的记事本打开并能读懂里面的内容,就用字符流。其他用字节流。 如果你什么都不知道,就用字节流

常用基类

字节流的抽象基类: InputStream ,OutputStream。

字符流的抽象基类: Reader , Writer。

注:由这四个类派生出来的子类名称都是以其父类名作为子类名的后缀。 如:InputStream的子类FileInputStream。 如:Reader的子类FileReader。

字节输出流 OutputStream

FileOutputStream 

构造方法

FileOutputStream(File file)

FileOutputStream(String name)

字节流写数据的方式

public void write(int b)

public void write(byte[] b)

public void write(byte[] b,int off,int len)

字节输入流 InputStream

FileInputStream

构造方法

FileInputStream(File file)

FileInputStream(String name)

字节流读数据的方式

public int read()

public int read(byte[] b)

字节缓冲流

字节流一次读写一个数组的速度明显比一次读写一个字节的速度快很多,这是加入了数组这样的缓冲区效果,java本身在设计的时候,也考虑到了这样的设计思想(装饰设计模式后面讲解),所以提供了字节缓冲区流

字节缓冲输出流 BufferedOutputStream

字节缓冲输入流 BufferedInputStream

【java】实例 字节缓冲流的使用_老坛酸菜吃鸭子的博客-CSDN博客_java 缓冲流实例

字符流

字符流=字节流+编码表。

字符流操作要注意的问题 :flush()的作用 flush()和close()的区别 

【java】字符流_老坛酸菜吃鸭子的博客-CSDN博客

OutputStreamWriter 字符输出流

public OutputStreamWriter(OutputStream out)

public OutputStreamWriter(OutputStream out,String charsetName)

写数据

public void write(int c)

public void write(char[] cbuf)

public void write(char[] cbuf,int off,int len)

public void write(String str)

public void write(String str,int off,int len)

InputStreamReader 字符输入流

public InputStreamReader(InputStream in)

public InputStreamReader(InputStream in,String charsetName)

读数据

public int read()

public int read(char[] cbuf)

【java】IO流实例 复制文本_老坛酸菜吃鸭子的博客-CSDN博客

操作基本数据类型的流

DataInputStream

DataOutputStream 

内存操作流

操作字节数组

ByteArrayInputStream

ByteArrayOutputStream

操作字符数组

CharArrayReader

CharArrayWrite

操作字符串

StringReader

StringWriter

打印流

特点:

只能操作目的地,不能操作数据。

可以操作任意类型的数据。

如果启动了自动刷新,能够自动刷新。

可以操作文件的流

字节流打印流

字符打印流
 

标准输入输出流

System类中的字段:in,out。

它们各代表了系统标准的输入和输出设备。

默认输入设备是键盘,输出设备是显示器。

System.in的类型是InputStream.

System.out的类型是PrintStream是OutputStream的子类FilterOutputStream 的子类.

随机访问流RandomAccessFile

RandomAccessFile类不属于流,是Object类的子类。但它融合了InputStream和OutputStream的功能。支持对随机访问文件的读取和写入。 

合并流SequenceInputStream

SequenceInputStream类可以将多个输入流串流在一起,合并为一个输入流,因此,该流也被称为合并流。

SequenceInputStream的构造方法

SequenceInputStream(InputStream s1, InputStream s2)

SequenceInputStream(Enumeration<? extends InputStream> e)

序列化流

序列化流 ObjectOutputStream

反序列化流 ObjectInputStream

序列化操作问题

为什么要实现序列化?

如何实现序列化?

序列化数据后,再次修改类文件,读取数据会出问题,如何解决呢?

使用transient关键字声明不需要序列化的成员变量 

Properties集合

是一个Map体系的集合类

Properties作为Map集合的使用

Properties的特殊功能

public Object setProperty(String key,String value)

public String getProperty(String key) public Set<String> stringPropertyNames()

Properties和IO流的结合使用

public void load(Reader reader)

public void store(Writer writer,String comments)

NIO包下的IO流

NIO其实就是新IO的意思。 JDK4出现NIO。新IO和传统的IO有相同的目的,都是用于进行输入输出的,但新IO使用了不同的方式来处理输入输出,采用内存映射文件的方式,将文件或者文件的一段区域映射到内存中,就可以像访问内存一样的来访问文件了,这种方式效率比旧IO要高很多,但是目前好多地方我们看到的还是旧IO的引用,所以我们仍以旧IO为主,知道NIO即可。

JDK7的IO改进(写一个案例) Path Paths Files

多线程

假如一个程序有多条执行流程,那么,该程序就是多线程程序。

进程: 正在运行的程序,是系统进行资源分配和调用的独立单位。 每一个进程都有它自己的内存空间和系统资源。

线程: 是进程中的单个顺序控制流,是一条执行路径 一个进程如果只有一条执行路径,则称为单线程程序。 一个进程如果有多条执行路径,则称为多线程程序。

Java程序运行原理: java 命令会启动 java 虚拟机,启动 JVM,等于启动了一个应用程序,也就是启动了一个进程。该进程会自动启动一个 “主线程” ,然后主线程去调用某个类的 main 方法。所以 main方法运行在主线程中。在此之前的所有程序都是单线程的。

思考: jvm虚拟机的启动是单线程的还是多线程的? 多  why?垃圾回收线程加上前面的主线程,最低启动了两个线程

Thread类的基本获取和设置方法

public final String getName()

public final void setName(String name)

多线程的实现

继承Thread类

定义一个类Mythread继承Thread类

在Mythread类中重写run()方法

创建Mytread类的对象

启动线程(start()方法)

实现Runnable接口

定义一个类Myrunnable继承Runnable类

在Myrunnable类中重写run()方法

创建Myrunnable类的对象

创建Thraed类的对象,把Myrunnable对象作为构造方法的参数

启动线程(start()方法)

卖票实例

public class SellTicket implements Runnable {
 
	private int tickets=100;
	private Object o=new Object();
	
	@Override
	public void run() {
		while(true) {
			synchronized(o) {//同步代码块,防止出现数据安全问题,也可以采用同步方法或同步静态方法
			if(tickets>0) {
				System.out.println(Thread.currentThread().getName()+"正在卖倒数第"+tickets+"张票");
				tickets--;
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					// TODO 自动生成的 catch 块
					e.printStackTrace();
				}
			}
		}
		}
 
	}
 
}
 
 
public class TicketDemo {
 
	public static void main(String[] args) {
		SellTicket s=new SellTicket();//创建实现了Runnable接口的类的对象
		Thread t1=new Thread(s,"一号窗口");//创建Thread类的对象,把实现了Runnable接口的类的对象作为构造方法的参数,并起名
		Thread t2=new Thread(s,"二号窗口");
		Thread t3=new Thread(s,"三号窗口");
 
	    t1.start();//启动线程
	    t2.start();
	    t3.start();
	}
 
}

实现Callable接口(略)

run()方法和start()方法的区别?

       start()方法是线程内的方法,run()方法是接口Runnable的方法(这个接口内只有这一个方法)/thread类的⼀个普通⽅法。

       start()⽅法才是调用该线程的争取方法,start()方法会使该线程进入准备阶段,当初始化完毕后jvm虚拟机会自动调用run()方法执行。start()方法只能被调用一次,因为一个线程只能被初始化一次。

       直接调用run()方法,没有准备的哪一个阶段,相当于调用一个类的普通的run()方法。run()方法可以调用多次。

匿名内部类方式使用多线程

new Thread(){代码…}.start();

New Thread(new Runnable(){代码…}).start(); 

线程调度

假如我们的计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得到 CPU时间片,也就是使用权,才可以执行指令。

那么Java是如何对线程进行调用的呢?

线程有两种调度模型: 分时调度模型   所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片 。抢占式调度模型   优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些。

Java使用的是抢占式调度模型。

如何设置和获取线程优先级

public final int getPriority()

public final void setPriority(int newPriority)

线程控制

线程休眠

public static void sleep(long millis)

线程加入

public final void join()

线程礼让

public static void yield()

后台线程

public final void setDaemon(boolean on)

中断线程

public final void stop() public void interrupt()

线程的生命周期图

线程安全问题

首先想为什么出现问题?(也是判断是否有问题的标准)

是否是多线程环境 是否有共享数据 是否有多条语句操作共享数据

如何解决多线程安全问题呢?

基本思想:让程序没有安全问题的环境。 怎么实现呢? 把多个语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可。

同步代码块

格式:         

synchronized(对象){

需要同步的代码;

}

同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。

同步的前提 多个线程 多个线程使用的是同一个锁对象

同步的好处 同步的出现解决了多线程的安全问题

同步的弊端 当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的,无形中会降低程序的运行效率。

同步方法

就是把同步关键字加到方法上

同步方法的锁对象是什么呢? this

如果是静态方法,同步方法的锁对象又是什么呢? 该类的字节码对象

如果锁对象是this,就可以考虑使用同步方法。 否则能使用同步代码块的尽量使用同步代码块。

为什么wait(),notify(),notifyAll()定义在Object类中而不是Thread类? 

  (wait(),notify(),notifyAll()方法只能定义在同步方法内或者同步代码块中使用,实现了两个线程间的通信机制)

    线程为了进入临界区(也就是同步块内),需要获得锁并等待锁可用,他们并不知道哪些线程持有锁,他们只需要知道当前资源是否被占用,是否可以获得锁,所以锁的持有状态该由同步监视器来获取,而不是线程本身

sleep()方法和wait()方法的区别?

相同点:一旦执行方法,都可以使当前进程进入阻塞状态

区别:

1,继承位置 Thread类 sleep();Object类 wait()

2,调用的位置 sleep()可以在任何场景下调用,wait()必须在同步代码块中调用

3,关于是否释放同步监视器 如果两个方法都使用在同步代码块或者同步方法中,sleep()不会释放锁,wait()会释放锁

4,是否可以传入参数 sleep()必须传入参数,wait()可以传入也可以不传入参数,传入参数就是在参数结束的时间开始等待,不传入参数就是直接等待

Lock锁

虽然我们可以理解同步代码块和同步方法的锁对象问题,但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

void lock()

void unlock()

死锁问题

同步弊端:效率低

如果出现了同步嵌套,就容易产生死锁问题

死锁问题及其代码 是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待现象

同步代码块的嵌套案例

线程间通信

针对同一个资源的操作有不同种类的线程 举例:卖票有进的,也有出的。

通过设置线程(生产者)和获取线程(消费者)针对同一个流水线生产产品对象进行操作

 生产者消费者问题

【java】多线程 生产者消费者问题 共享资源区的大小 实例_老坛酸菜吃鸭子的博客-CSDN博客

线程的状态转换图

线程组

Java中使用ThreadGroup来表示线程组,它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。

默认情况下,所有的线程都属于主线程组。

public final ThreadGroup getThreadGroup()

我们也可以给线程设置分组

Thread(ThreadGroup group, Runnable target, String name) 

线程池

程序启动一个新线程成本是比较高的,因为它涉及到要与操作系统进行交互。而使用线程池可以很好的提高性能,尤其是当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。

线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

在JDK5之前,我们必须手动实现自己的线程池,从JDK5开始,Java内置支持线程池

JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法

public static ExecutorService newCachedThreadPool()

public static ExecutorService newFixedThreadPool(int nThreads)

public static ExecutorService newSingleThreadExecutor()

这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法

Future<?> submit(Runnable task) <T>

Future<T> submit(Callable<T> task)

定时器

定时器是一个应用十分广泛的线程工具,可用于调度多个定时任务以后台线程的方式执行。

在Java中,可以通过Timer和TimerTask类来实现定义调度的功能

Timer

public Timer()

public void schedule(TimerTask task, long delay)

public void schedule(TimerTask task,long delay,long period)

TimerTask

public abstract void run() public boolean cancel()

开发中

Quartz是一个完全由java编写的开源调度框架。

网络编程

就是用来实现网络互连的不同计算机上运行的程序间可以进行数据交换

java网络编程相关类

 IP地址:InetAddress /InetSocketAddress

URL UDP:    DatagramSocket,DatagramPacket

TCP:ServerSocket Socket 

UDP通信原理

java提供了DatagramSocket类作为基于UDP协议的Socket,DatagramPocket类表示数据报包,使用此类对象创建数据并把数据打包

//UDP发送数据

import java.io.IOException;
import java.net.*;
 
public class UDPSocketSend {
    public static void main(String[] args) throws IOException {
        //创建发送端的Socket对象
        DatagramSocket address=new DatagramSocket();
        //创建数据,并把数据打包
        byte[] bys="hello world".getBytes();
        DatagramPacket ds=new DatagramPacket(bys,bys.length,InetAddress.getByName("172.20.2.154"),10086);
        //调用DatagramSocket对象的方法发送数据
        address.send(ds);
        //关闭发送端
        address.close();
    }
}


//UDP接收数据

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
 
public class UDPReceive {
    public static void main(String[] args) throws IOException {
        //创建接收端的Socket对象
        DatagramSocket ds=new DatagramSocket(10086);
        //创建数据包,用于接收数据
        byte[] bys=new byte[1024];
        DatagramPacket dp=new DatagramPacket(bys,bys.length);
        //利用DatagramSocket对象的方法接收数据
        ds.receive(dp);
        //解析数据包,并把数据在控制台上显示
        //byte[] getData() 返回数据缓冲区
        byte[] data=dp.getData();
        String dataString=new String(data,0,data.length);
        System.out.println("数据是"+dataString);
        //关闭接收端
        ds.close();
    }
}

TCP通信原理

public class ChatroomClient {
private static Socket client;
public ChatroomClient() throws UnknownHostException, IOException {
super();
client = new Socket("localhost", 9999);
new Thread(new Receive()).start();}
public static void main(String[] args) throws UnknownHostException, IOException {
// TODO Auto-generated method stub
new ChatroomClient();
DataOutputStream dos = new DataOutputStream(client.getOutputStream());
System.out.println("请输入昵称:");
Scanner sc = new Scanner(System.in);
String name = sc.nextLine();
dos.writeUTF(name);
boolean flag = true;
while(flag) {
String msg = sc.nextLine();
dos.writeUTF(msg);}}}

public class Receive implements Runnable {
@Override
		public void run() {
			// TODO Auto-generated method stub
			while(true) {
				try {
					InputStream is = client.getInputStream();
					DataInputStream dis = new DataInputStream(is);
					System.out.println(dis.readUTF());
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}}


反射

java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用他的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制

可以在运行时加载、探知、使用编译期间完全未知的类        

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;

Class c = Class.forName(“com.g.reflection.Student”)

加载完类后,在堆内存中,产生了一个Class类型的对象(一个类只有一个Class对象,类似该类的设计图,一般只有一张,按设计图可生产多个对象),这个Class对象中包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为:反射 

【java】反射机制_老坛酸菜吃鸭子的博客-CSDN博客

获取class对象

1.使用类的class属性来获取该类对应的class对象

Class<Student> c1=Student.class;


2.调用对象的getClass()方法,返回该对象所属类对应的Class对象

Student s=new Student();
Class<? extends Student> c2=s.getClass();


3.使用该Class类中的静态方法forName(String className)

该方法需要传入字符串参数,该字符串参数的值是某个类的全路径,也就是完整包名的路径

Class<?> c4=class.forName("test.Student");


 

获取类名

Class.getName()   以String的形式,返回Class对象的“实体”名称;

Class.getSimpleName()   获取源代码中给出的“底层类”简称。

获取构造方法并使用

Constructor<?> [] getConstructors() 返回一个包含Constructor对象的数组,Constructor对象反映了由该对对象表示的类的所有公共构造函数

Constructor<?> [] getDeclaredConstructors() 返回反映由该class对象表示的类声明的所有构造函数的Constructor对象的数组

Constructor<T> [] getConstructor()(Class<?>...parameterTypes)   返回单个公共构造方法的对象

参数:对应的字节码对象

Constructor<T> [] getDeclaredConstructors()(Class<?>...parameterTypes) 返回单个构造方法对象

//获取构造器
Constructor[] constructors = clazz.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println("构造器:"+constructor);
}
Constructor c = clazz.getDeclaredConstructor(String.class,int.class);
System.out.println("获取带参构造器:"+c);
Constructor c2 = clazz.getDeclaredConstructor(null);
System.out.println("获取无参构造器:"+c2);
}


Constructor类中用于调用构造方法的方法

T newInstance(object...initargs)  根据指定的构造方法创建对象

//通过反射API动态调用无参构造方法,构造对象
Constructor<User> c1 = clazz.getDeclaredConstructor();
User u1 = c1.newInstance();
System.out.println(u1);
//通过反射API动态调用带参构造,构造对象
Constructor<User> c2 = clazz.getDeclaredConstructor(String.class,int.class);
User u2 = c2.newInstance("a",13);
System.out.println(u2.getName());

获取成员方法并使用

Method[] getMethods()   返回所有公共成员方法对象的数组,包括继承的

Method getDeclaredMethods()   返回所有成员方法对象的数组,不包括继承的

Method getMethod(String name,Class<?>... parameterTypes)    返回单个公共成员方法对象

Method getDeclaredMethod(String name,Class<?>... parameterTypes)   返回单个成员方法对象

//获取方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println("方法:"+method);}
Method m01 = clazz.getMethod("getAge", null);
//如果方法有参,则必须传递参数类型对应的class对象
Method m02 = clazz.getDeclaredMethod("setAge", int.class);
Method m03 = clazz.getDeclaredMethod("setAge", null);
System.out.println(m01);
System.out.println(m02);
System.out.println(m03);


Method类中用于调用成员方法的方法

Object invoke(Object obj,Object...args) 调用obj对象的成员方法,参数是args,返回值是Object类型

//通过反射API动态调用普通方法
User u3 = c1.newInstance();
Method m1 = clazz.getDeclaredMethod("setName", String.class);//u3.setName("张三"): 
m1.invoke(u3, "张三");//需要调用的方法名和参数,变成了字符串,运行时改变方法名字符串可调用不同的方法
System.out.println(u3.getName());


获取成员变量并使用

Field[] getFields()   返回所有公共成员变量对象的数组

Field[] getDeclaredFields()   返回所有成员变量的数组

Field getField(String fieldName)   返回单个公共成员变量

Field getDeclaredField(String fieldName)   返回单个成员变量对象

Field类中用于给成员变量赋值的方法

void set(Object obj,Object value) 给obj对象的成员变量赋值为value

//使用反射API动态设置属性
User u4 = c1.newInstance();
Field f1 = clazz.getDeclaredField("name");
f1.setAccessible(true);//这个属性不需要做安全检查,可以直接访问
f1.set(u4, "李四");//通过反射直接写属性
System.out.println(u4.getName());
System.out.println(f1.get(u4));//通过反射直接读属性
 

public class User {
    private String name;
    private int age;

    public User() {
        super();
    }

    public User(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setAge() {
        this.age = 0;
    }

}


import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Scanner;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
            //1.获取Class对象
            Class c = Class.forName("User");
            //2.获取类的构造方法
            Constructor<User> con = c.getConstructor();
            //3.使用类的构造方法,并创建实例化对象
            User u = con.newInstance();
            //4.使用反射API动态调用普通方法
                //4.1获取User的年龄跟名字
                Scanner sc = new Scanner(System.in);
                System.out.println("请输入用户名字:");
                String name = sc.nextLine();
                System.out.println("请输入用户年龄:");
                int age = sc.nextInt();
                //4.2获取类的成员方法
                Method m1 =c.getDeclaredMethod("setName",String.class);
                m1.invoke(u,name);
                Method m2 = c.getDeclaredMethod("setAge",int.class);
                m2.invoke(u,age);
                System.out.println("使用反射API动态调用普通方法:");
                System.out.println(u.getName()+" "+u.getAge());
    }
}

JDBC编程

JDBC(Java DataBase Connectivity)就是用Java语言来操作数据库。

之前我们学习了操作数据库是在控制台使用SQL语句来操作数据库,JDBC是用Java语言向数据库发送SQL语句,从而可以中java程序中操作数据库。 

JDBC是接口,而数据库驱动才是接口的实现,没有驱动无法完成数据库连接

JDBC核心类

JDBC中的核心类有:DriverManager、Connection、Statement,和ResultSet。

DriverManger(驱动管理器)的作用有两个:

   注册驱动:这可以让JDBC知道要使用的是哪个数据库Oracle还是MySQL;

   获取Connection:如果可以获取到Connection,那么说明已经与数据库连接上了。 

JDBC连接数据库

import java.sql.Connection;
import java.sql.DriverManager;

public class DB {
	//数据库地址
	private String Driver_name ="jdbc:mysql://localhost:3306/bookmanagement?serverTimezone=Asia/Shanghai&useTimezone=true";
	//数据库用户名
	private String USER = "root";
	//数据库密码
	private String PASS = "";
	//数据库连接
	public static Connection con;
	//构造方法
	public DB(){
		try {
			//加载驱动
			Class.forName("com.mysql.cj.jdbc.Driver");
			//获取连接
			con = DriverManager.getConnection(Driver_name, USER, PASS);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	//获取连接
	public static Connection getConnection(){
		if(con == null){
			new DB();
		}
		return con;
	}
}



【JDBC-1】jdbc编程六大步骤_Do My Love的博客-CSDN博客_jdbc编程的六个步骤

GUI

【java】GUI 各种组件使用方法与应用实例_老坛酸菜吃鸭子的博客-CSDN博客_javagui例子

菜单组件

MenuBar,Menu,MenuItem

先创建菜单条,再创建菜单,每一个菜单中建立菜单项。 也可以菜单添加到菜单中,作为子菜单

菜单的创建可以遵循以下步骤:

1. 创建一个菜单栏,将菜单栏放置在frame的顶部

2. 拉动菜单控件到菜单栏中

3. 拉动菜单控件到每个菜单中可以建立一个子菜单

4. 拉动菜单项控件到菜单控件中建立一个菜单项

import java.awt.Color;
 
import java.awt.Frame;
 
import java.awt.Menu;
 
import java.awt.MenuBar;
 
import java.awt.MenuItem;
 
import java.awt.event.ActionEvent;
 
import java.awt.event.ActionListener;
 
import java.awt.event.WindowAdapter;
 
import java.awt.event.WindowEvent;
 
// 主窗体
 
public class MyFrame extends Frame {
 
private static final long serialVersionUID = 6895463895656626294L;
 
private Frame frmMain; // 窗体
 
MenuBar mb; // 菜单栏
 
Menu mnuFile; // "文件"菜单
 
Menu mnuEdit; // "编辑"菜单
 
MenuItem miOpen; // "打开"菜单项
 
MenuItem miSave; // "保存"菜单项
 
MenuItem miClose; // "关闭"菜单项 
 
MenuItem miCopy; // "复制"菜单项 
 
MenuItem miPaste;  // "粘贴"菜单项
 
public MyFrame() { 
 frmMain = new Frame("主窗体"); 
// 创建菜单栏
 mb = new MenuBar(); 
// 创建菜单
 mnuFile = new Menu("文件"); 
mnuEdit = new Menu("编辑"); 
// 创建菜单项 
 miOpen = new MenuItem("打开"); 
 miSave = new MenuItem("保存"); 
 miClose = new MenuItem("关闭");
 miCopy = new MenuItem("复制");
 miPaste = new MenuItem("粘贴");
 } 
public void showFrame( ){
 frmMain.setSize(800, 600);
 frmMain.setLocation(100, 100); 
 frmMain.setBackground(Color.white);
 frmMain.setVisible(true; frmMain.setLayout(null; frmMain.addWindowListener(new WindowHandler()));
 // 注册窗口监听器 // 将菜单栏放入窗体中
 frmMain.setMenuBar(mb); 
 // 将菜单放入菜单栏中
 mb.add(mnuFile; mb.add(mnuEdit);
 // 将菜单项放入菜单中 
 mnuFile.add(miOpen);
 mnuFile.add(miSave);
 mnuFile.add(miClose);
 mnuEdit.add(miCopy);
 
 mnuEdit.add(miPaste);
 // 注册动作事件监听器 
 miClose.setActionCommand("miClose_Clicked");
 miClose.addActionListener(new MenuHandler(); 
} 
// 定义一个内部类,在这个类中编写窗口关闭事件处理程序。
 private class WindowHandler extends WindowAdapter { 
 public void windowClosing(WindowEvent e {
 System.exit(0);
 // 退出应用程序,状态码 0 表示正常终止,非 0 表示异 常终止。
 });
 } 
// 定义一个内部类,在这个类中编写动作事件处理程序。
 private class MenuHandler implements ActionListener {
 public void actionPerformed(ActionEvent e { 
  if (e.getActionCommand( )== "miClose_Clicked" ){ 
     System.exit(0; // 退出应用程序
   } 
}
}
} 

//测试类
public class TestMyFrame 
{ 
  public static void main(String[] args) {
  // 启动主窗体 
  MyFrame guiWindow = new MyFrame(); 
  guiWindow.showFrame();
 } 
}

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老坛酸菜吃鸭子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值