JavaSE基础(W5.5)总结
Day1
IO流的分类
按流的方向划分:
1)输入流
2)输出流
按流的类型划分:
1)字节流
字节输入流:InputStream(抽象类)
FileInputStream:针对文件操作的字节输入流(读)
字节缓冲输入流(字节高效输入流):BufferedInpuStream
字节输出流:OutputStream(抽象类)
FileOutputStream:针对文件操作的字节输出流(写)
字节缓冲输出流(字节高效输出流):BufferedOutputStream
2)字符流:由于字节流操作文本文件的时候(一次读取一个字节的时候,将内容输出在控制台上:可能出现中文乱码)所以才有了字符流!
字符输入流:Reader:读
字节输入流通向字符输入流的桥梁(转换输入流):InputStreamReader
为了书写简单:FileReader
字符缓冲输入流(字符高效输入流):BufferedReader
特有功能:String readLine() :一次读取一行
字符输出流:Writer:写
字节输出流流通向字符输出流的桥梁(转换输出流):OutputStreamWriter
为了书写简单:FileWriter
字符缓冲输出流(字符高效输出流):BufferedWriter
特有功能:
public void newLine():写入一个行的分隔(换行功能)
字节流:
字节输出流:OutputStreamStream抽象类
提供具体的子类:FileOutputStream
使用步骤 :
1)创建一个文件输出流对象
2)写一些内容(输出到某个盘符下或者当前项目下)
3)释放资源:流资源(流的底层----->非Java语言实现:本地方法)
字节输出流:写的功能
public void write(int b) throws IOException:给当前字节输出流中写入一个字节
public void write(byte[] b) throws IOException:写入一个字节数组
public void write(byte[] b,int off,int len)throws IOException:写一个字节数组的一部分
参数2:从指定位置开始
参数3:指定长度
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
//具体类创建
FileOutputStream fos = new FileOutputStream("fos.txt") ; //调用系统资源 执行当前地址:文件fos.txt
//写
fos.write("hello,io".getBytes());
//释放资源:将当前系统资源指向的这个文件将它从内存中释放调用
fos.close() ;
}
}
//------------
public class FileOutputStreamDemo2 {
public static void main(String[] args) throws IOException {
//创建一个输出流对象
FileOutputStream fos = new FileOutputStream("fos2.txt") ;
//public void write(int b) throws IOException:给当前字节输出流中写入一个字节
// public void write(byte[] b) throws IOException:写入一个字节数组
byte[] bytes = {97,98,99,101} ;
fos.write(bytes) ;
fos.write(bytes,0,2);
//释放资源
fos.close() ;
}
}
//--------------------------
构造方法
public FileOutputStream(String name,boolean append) throws FileNotFoundException
创建一个文件输出流对象,第二个参数为true,就是在文件字节末尾处追加!
如何现在将输出一句内容,换一行?
windows操作系统:换行符号"\r\n"
public class FileOutputStreamDemo3 {
public static void main(String[] args) throws IOException {
//创建一个文件输出流对象,开启文件末尾字节追加
FileOutputStream fos = new FileOutputStream("fos3.txt",true) ;
//for循环
for(int x = 0 ; x < 10 ; x ++){
fos.write(("hello"+x).getBytes());
//写入一个换行符号
fos.write("\r\n".getBytes());
}
//关闭资源
fos.close();
}
}
//-------------------------------
流中加入异常操作:解决方案---->try...catch...finally 标准格式
public class FileOutputStreamDemo4 {
public static void main(String[] args) {
//method1() ;
// method2() ;
method3() ;
}
//第三种方式:try...catch...finally
private static void method3() {
FileOutputStream fos = null ;
try {
fos = new FileOutputStream("fos4.txt") ;
fos.write("hello,i'm coming...".getBytes());
} catch (IOException e) {
e.printStackTrace(); //如果try有问题:代码追踪到源码中,并且有jvm将异常信息以及源码的错误行数都可以 控制台日志体现
}finally {
if(fos!=null){
//释放资源
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
//第二种方式:try...catch...catch
private static void method2() {
//创建一个文件输出流对象
FileOutputStream fos = null;
try {
fos = new FileOutputStream("fos4.txt");
//写数据
fos.write("hello,JavaEE".getBytes());
//关闭资源
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//第一种方式:就是分别try...catch
private static void method1() {
//创建一个文件输出流对象
FileOutputStream fos = null ;
try {
fos = new FileOutputStream("fos4.txt") ;
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//写数据
try {
fos.write("hello,OutputStream".getBytes());
} catch (IOException e) {
e.printStackTrace();
}
//释放资源
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
抽象类:InputStream:表示字节输入流的所有类的超类
提供的针对文件操作的输入流:FileInputStream
使用步骤:
1)创建文件操作输入流对象
public InputStream()
2)通过 文件字节输入流对象,读取指定的文件中的内容
读取数据的功能:
public int read() throws IOException:一次读取一个字节
public int read(byte[] b) throws IOException: 读取一个字节数组,返回的是读取的实际字节数
public int read(byte[] b,int off,int len) throws IOException:读取一部分字节数组
3)释放资源
一次读取一个字节:
读取一些文件,中文会出现乱码,原因就是将实际的字节数强制转为char类型,
而中文在idea平台:utf-8格式:一个中文对应三个字节,和前面的英文拼接不到一起,就出现中文乱码
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
//创建文件操作输入流对象
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java") ;
//将获取,判断,赋值直接一次性使用
//声明一个字节数
int by = 0 ;
while((by=fis.read())!=-1){
System.out.print((char)by);
}
//释放资源
fis.close();
}
}
public int read(byte[] b) throws IOException: 读取一个字节数组,返回的是读取的实际字节数
字节输入流 一次读取一个字节/一次读取一个字节数组 (第二种方式的读写速率优于第一种方式!)
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
byte[] bufferBytes = new byte[1024] ;
//实际字节数
int len = 0 ;
//赋值,判断,获取
while((len=fis.read(bufferBytes))!=-1){
//获取内容 :一定带上 0,实际字节数
System.out.println(new String(bufferBytes,0,len));
}
//释放资源
fis.close();
}
}
复制文件
使用文件字节输入流:FileInputStream :一次读取一个字节/一次读取一个字节数组
当前输入流对象指向:FileOutputStreamDemo.java
目标文件--->需要复制的盘符地址
使用文件字节输出流:FileOutputStream: 写一个字节/写一个字节数组,从0开始,写入实际长度
public class CopyFileDemo {
public static void main(String[] args) throws Exception {
//创建一个文件字节输入流对象
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java") ;
//创建一个文件字节输出流对象
FileOutputStream fos = new FileOutputStream("D:\\要复制到某个盘符") ;
long start = System.currentTimeMillis() ;
//读写复制操作
//方式1:一次读取一个字节
// int by = 0 ;
// while((by=fis.read())!=-1){
//读一个字节,写入一个字节
// fos.write(by);
// }
//方式2:一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
//写入一个字节数组,并且从0开始,写入实际的字节数
fos.write(bytes,0,len);
}
long end = System.currentTimeMillis() ;
System.out.println("共耗时:"+(end-start)+"毫秒");
//关闭资源
fos.close();
fis.close();
}
}
复制图片
将当前项目目录下的图片复制到某个盘符下
public class CopyImage {
private static FileOutputStream fos = null ;
private static FileInputStream fis = null ;
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis() ;
// copy("图片.jpg","D:\\需要复制的盘符地址\\图片.jpg") ;
copy2("图片 .jpg","D:\\需要复制的盘符地址\\图片.jpg") ;
close(fos,fis) ;
long end = System.currentTimeMillis() ;
System.out.println("共耗时"+(end-start)+"毫秒");
}
//一次读取一个字节数组
private static void copy2(String srcFile, String destFile) throws Exception {
//封装源文件--字节输入流对象
fis = new FileInputStream(srcFile) ;
//封装目的地文件
fos = new FileOutputStream(destFile) ;
//读写操作
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
close(fos,fis);
}
//一次读取一个字节
private static void copy(String srcFile, String destFile) throws Exception {
//封装源文件--字节输入流对象
fis = new FileInputStream(srcFile) ;
//封装目的地文件
fos = new FileOutputStream(destFile) ;
//读写操作
int by = 0 ;
while((by=fis.read())!=-1){
fos.write(by);
}
close(fos,fis);
}
//流资源关闭的功能
private static void close(FileOutputStream fos,FileInputStream fis) {
if(fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(fis!=null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
缓冲流复制
Java提供了比一次读取一个字节数组更高效的方式:缓冲流
BufferedOutputStream
BufferedOutputStream(OutputStream out) :指定默认的缓冲长度:足够大了
写
public void write(int b)
public void write(byte[] b,int off,int len)
BufferedInputStream
BufferedInputStream(InputStream in)
读
public int read()
public int read(byte[] bytes)
public int read(byte[] bytes,int offset,int len)
内部只是提供一个字节数组(缓冲区):长度8192个长度
构造方法都是默认的缓冲区大小,文件的操作还需要通过最底层的基本的字节流操作
缓冲流都是不直接操作文件,仅仅是提供内部缓冲区(提高读写效率!)
public class BufferedStreamDemo {
public static void main(String[] args) throws Exception{
//创建一个字节缓冲输入流对象:
BufferedInputStream bis = new BufferedInputStream(
new FileInputStream("FileOutputStreamDemo.java")) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
System.out.println(new String(bytes,0,len));
}
//关闭
bis.close();
}
}
视频文件复制
将D盘下的冒泡.mp4视频文件复制到当前项目下的copy.mp4
使用基本的字节流一次读取一个字节数组
耗时247毫秒
使用字节缓冲流一次读取一个字节数组
耗时78毫秒
针对一个文件读写复制几种方式?
基本的字节流:一次一个字节
基本的字节流:一次一个字节数组
字节缓冲流:一次一个字节
字节缓冲流:一次一个字节数组
public class CopyMp4 {
public static void main(String[] args) throws Exception{
long start = System.currentTimeMillis() ;
// copyMp4("D:\\冒泡.mp4","copy.mp4") ;
copyMp4_2("D:\\冒泡.mp4","copy.mp4") ;
long end = System.currentTimeMillis() ;
System.out.println("耗时"+(end-start)+"毫秒");
}
//高效流:字节缓冲输入流一次读取一个字节数组
private static void copyMp4_2(String src, String dest) throws Exception {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src)) ;
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(dest)) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
//释放
bos.close();
bis.close();
}
//基本的字节流读写复制(一次读取一个字节数组)
private static void copyMp4(String src, String dest) throws Exception {
FileInputStream fis = new FileInputStream(src) ;
FileOutputStream fos = new FileOutputStream(dest) ;
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = 0 ;
while((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
//释放
fos.close();
fis.close();
}
}
字符流
字符流
字符输入
字符输出
Writer(抽象类)
子类:字符转换输出流:OutputStreamWriter 是字符流通向字节流的桥梁
构造方法:
OutputStreamWriter(OutputStream out) :创建转换输出流对象:平台默认编码集(utf-8)
OutputStreamWriter(OutputStream out,String charsetName):使用指定的字符集编码
public class OutputStreamWriterDemo {
public static void main(String[] args) throws Exception{
//创建一个字符输出流对象
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("osw.txt"),"utf-8") ;
OutputStreamWriter osw = new OutputStreamWriter(
new FileOutputStream("osw.txt")) ;
osw.write("hello,字符流");
//关闭流的之前,刷新该流(将字符流的内存中底层保存的字节刷新)
osw.flush();
//关闭资源 --- 关闭系统资源指向文件的 线程!
osw.close(); //内存对象已经为null(流已经关闭)
字符输入
Reader(抽象类)
InputStreamReader 是字节流通向字符流的桥梁
构造方法:
public InputStreamReader(InputStream in):使用默认字符集进行解码(utf-8:跟idea的配置有关系)
public InputStreamReader(InputStream in,String charsetName):使用指定的字符集进行解码
在读写的时候,必须要保证编码和解码统一!
public class InputStreamReaderDemo {
public static void main(String[] args) throws Exception{
//创建字符输入流对象:使用字符转换输入流
InputStreamReader isr =
new InputStreamReader(new FileInputStream("osw.txt"));
//一次读取一个字符数组
char[] chs = new char[1024] ;
int len = 0 ;
while((len=isr.read(chs))!=-1){
System.out.println(new String(chs,0,len));
}
//释放
isr.close();
}
}
字符流复制文件
针对图片文件,视频文件,音频文件等等----都是直接使用字节流!
字符转换流的便捷类:只是为了书写简单
InputStreamReader---->FileReader(File file)/FileReader(String pathname) :平台默认的解码集(idea---utf-8)
OutputStreamWriter --->FileWriter(File file)/FileWriter(String pathname):默认的编码
public class CopyFile {
public static void main(String[] args) throws Exception{
//针对文件操作的字符输入流
FileReader fr = new FileReader("CopyMp4.java") ;
//针对文件操作的字符输出流
FileWriter fw = new FileWriter("D:\\JavaEE_2104\\EE_day25\\code\\a.java");
//一次读取一个字符数组
char[] chs = new char[1024] ;
int len = 0 ;
while((len=fr.read(chs))!=-1){
//写
fw.write(chs,0,len);
//刷新
fw.flush() ;
}
//关闭
fw.close();
fr.close();
}
}
字符缓冲输入流和字符缓冲输出流:提供默认的缓冲区大小,读写的操作还需要交给底层字节流
为了针对文本文件操作,提高执行效率!
BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
构造方法
BufferedWriter(Writer out)
成员方法:
public void newLine():换行功能
字符缓冲输入流:BufferedReader
构造方法:
public BufferedReader(Reader in)
特有功能:
public String readLine()
public class BufferedStreamDemo {
public static void main(String[] args)throws Exception {
BufferedReader br = new BufferedReader(new FileReader("bw.txt")) ;
String line = null ;
while((line=br.readLine())!=null){
System.out.println(line);
}
//释放资源
br.close();
//读写复制操作:
//将当前项目下的OutputStreamWriterDemo.java复制D:\JavaEE_2104\EE_day25\code\\day25.java
//字符缓冲输入流
BufferedReader br2 = new BufferedReader(
new FileReader("OutputStreamWriterDemo.java")) ;
//字符缓冲输出流
BufferedWriter bw2 = new BufferedWriter(
new FileWriter("D:\\JavaEE_2104\\EE_day25\\code\\day25.java")) ;
String line2 = null ;
while((line2=br2.readLine())!=null){
bw2.write(line2);
bw2.newLine();
bw2.flush();
}
//关闭资源
bw2.close();
br2.close();
}
}
键盘录入三种
键盘录入三种
1)main方法的参数(早期的)
2)jdk5以后提供的Scanner
3)BufferedReader(Reader r)
Properties 继承自Hashtable<K,V>---->实现Map<K,V>接口
表示了一个持久的属性集
Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
构造方法
public Properties()Properties 继承自Hashtable<K,V>---->实现Map<K,V>接口
表示了一个持久的属性集
Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
构造方法
public Properties()public class Test {
public static void main(String[] args) throws Exception{
//创建一个字符缓冲输入流对象
// Scanner sc = new Scanner(System.in) ;
InputStream in = System.in ;
//抽象类指向子类
Reader r = new InputStreamReader(in) ;
BufferedReader br = new BufferedReader(r) ;
//提示
System.out.println("请您输入一个int类型的内容:");
String line = br.readLine(); //阻塞式方法: 不录入内容,一直等待
int i = Integer.parseInt(line); //line:数字字符串
System.out.println("您输入的数据是:"+i);
}
}
Day2
Properties
Properties 继承自Hashtable<K,V>---->实现Map<K,V>接口
表示了一个持久的属性集
Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
构造方法
public Properties()
public class PropertiesDemo {
public static void main(String[] args) {
//Properties没有泛型,属于Map的一个子实现类
//使用Map接口的功能操作
//创建一个属性列表
Properties properties = new Properties() ;
//put
properties.put("张三",30) ;
properties.put("李四",40) ;
properties.put("王五",50) ;
properties.put("赵六",25) ;
//遍历:Map集合遍历方式: 推荐:keySet()
Set<Object> keySet = properties.keySet();
for(Object obj :keySet){
//通过键获取值
Object value = properties.get(obj);
System.out.println(obj+"---"+value);
}
}
}
关于属性集合类的特有功能:
添加方法
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() ;
//添加
prop.setProperty("1","文章") ;
prop.setProperty("2","高圆圆") ;
prop.setProperty("3","马伊琍") ;
prop.setProperty("4","赵又廷") ;
prop.setProperty("4","王宝强") ;
//遍历
Set<String> keySet = prop.stringPropertyNames();
for(String key:keySet){
//通过键获取值
String value = prop.getProperty(key);
System.out.println(key+"---"+value);
}
}
}
关于属性集合类的应用;
1)因为键和值都是String,所以可能将键和值的保存在文本文件或者配置文件中 :加载过程
public void load(Reader reader)throws IOException
public void load(InputStream in)throws IOException
2)将属性集合类中的内容写出到某个文件中:保存过程
public void store(OutputStream out,String comments) throws IOException
参数1:当前字节输出流
参数2:给当前属性列表中写入完毕之后,注释的内容
public void store(Writer writer,String comments) throws IOException
将当前项目下的name.txt内容加载到属性集合类中
public class PropertiesDemo3 {
public static void main(String[] args) throws IOException {
// myLoad() ;
// mySotre() ;
}
//保存:将当前属性集合类中的内容,输出在某个文件中
private static void mySotre() throws IOException {
//创建一个属性列表
Properties prop = new Properties() ;
prop.setProperty("马伊琍","35") ;
prop.setProperty("文章","26") ;
prop.setProperty("姚笛","22") ;
prop.setProperty("王宝强","35") ;
prop.setProperty("马蓉","30") ;
//保存
prop.store(new FileWriter("userList.txt"),"name's list");
}
//加载:将name.txt内容加载到属性集合类中
private static void myLoad() throws IOException {
//创建一个属性集合类
Properties prop = new Properties() ;
System.out.println(prop);
//加载
//字符流
Reader r = new FileReader("name.txt") ;
prop.load(r);
//遍历
Set<String> keySet = prop.stringPropertyNames();
for (String key: keySet) {
String value = prop.getProperty(key) ;
System.out.println(key+"---"+value);
}
//System.out.println(prop);
}
}
如果我们的配置文件后缀名xx.properties
操作步骤:
src目录下---->类路径
将properties配置文件放置在src目录下
public class PropertiesDemo4 {
public static void main(String[] args) throws IOException {
InputStream inputStream = PropertiesDemo4.class.getClassLoader().getResourceAsStream("user.properties");
//创建属性集合类中
Properties prop = new Properties() ;
prop.load(inputStream);
//System.out.println(prop);
Set<String> keySet = prop.stringPropertyNames();
for(String key:keySet){
System.out.println(key+"---"+prop.getProperty(key));
}
}
}
获取本机ip字符串形式及主机名称UDP实现
一个具体类中,没有字段,没有构造方法,
那么这个类只有成员方法,成员方法里面存在静态功能,返回值是它本身!
单例模式:
Runtime
private static Runtime currentRuntime = new Runtime() ;
private Runtime(){}
public static Runtime getRuntime(){
return currentRuntime
}
public static InetAddress getByName(String host):给定主机名称,可以获取互联网ip地址对象!
参数:可以传递主机名称/ip地址名称
public String getHostAddress():获取ip地址字符串形式
public String getHostName():获取主机名称
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
InetAddress inetAddress = InetAddress.getByName("本机ip地址");
//获取ip地址字符串文本
String ip = inetAddress.getHostAddress();
System.out.println(ip);
//获取主机名称
String hostName = inetAddress.getHostName();
System.out.println(hostName);//本机名称
}
}
UDP协议发送端的实现步骤: (不需要建立连接通道,以"数据报包"的方式发送数据)
DatagramSocket表示用来发送和接收"数据报包"的套接字
1)创建发送端的Socket: DatagramSocket
public DatagramSocket() throws SocketException{}
2) 创建 "数据报包"对象
public DatagramPacket(byte[] buf,int length,InetAddress address,int port)
3)发送数据报包
public void send(DatagramPacket p) throws IOException
4)释放资源
close()关闭socket对象
public class SendDemo {
public static void main(String[] args) throws IOException {
//创建发送端的Socket: DatagramSocket
DatagramSocket ds = new DatagramSocket() ;
String messageStr = "输出字符" ;
byte[] bytes = messageStr.getBytes();
int length = bytes.length ;
InetAddress inetAddress = InetAddress.getByName("10" +
".12.152.129");
int port = 10086 ;
DatagramPacket dp = new DatagramPacket(bytes, length, inetAddress, port);
//3)发送数据
ds.send(dp);
System.out.println("当前数据已经发送...");
//4)释放资源
ds.close();
}
}
UDP协议接收端实现
UDP协议接收端实现
1)创建接收端的Socket
public DatagramSocket(int port) throws SocketException:绑定端口号
2)数据一个数据报包对象:DatagramPacket
接收容器
public DatagramPacket(byte[] buf, int length) :获取的是缓冲区的数据(不是真实数据)
一般情况:byte[] bytes = new byte[1024] ; 自定义字节缓冲区
3)接收
public void receive(DatagramPacket p):阻塞式方法:在接收数据之前,一直处于阻塞状态,直到
当前接收端监听客户端口号了
4) 获取缓冲区的传递的真实数据
public byte[] getData():获取真实的字节数组
public int getLength():获取实际长度
将获取的字节数据---->String(byte[] bytes,int offset,int length)
获取哪个发送端传递的数据:ip 文本形式:
public InetAddress getAddress()
IntegerAddss--->public String getHostAddress()
5)使用完毕,关闭接收端
接收端不能运行多次,否则出现异常了,端口号被占用!
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
System.out.println("接收端等待发送数据...");
//创建接收端的Socket
DatagramSocket ds = new DatagramSocket(10086) ;
// 接收容器:数据报包
//定义一个字节缓冲区
byte[] bytes = new byte[1024] ;
int length = bytes.length ;
DatagramPacket dp = new DatagramPacket(bytes,length) ;
//接收
ds.receive(dp);
System.out.println("已经获取发送数据准备解析...");
byte[] bytes2 = dp.getData();
int len = dp.getLength();
//获取ip地址
String ip = dp.getAddress().getHostAddress();
String receiveMsgStr = new String(bytes2,0,len) ;
System.out.println("data from " + ip +"and content is: "+receiveMsgStr);
//关闭资源
ds.close();
}
}
键盘录入,让接收端接收信息
udp发送端不断的键盘录入数据,当前录入是 "over/886",结束,接收端不断的接收数据!
键盘录入数据采用的是:BufferedReader的readLine()功能来操作
发送
public class SendDemo {
public static void main(String[] args) {
//创建一个字符缓冲输入流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
//创建一个送端的Socket对象
DatagramSocket ds = null ;
try {
ds = new DatagramSocket() ;
String line = null ;
while((line=br.readLine())!=null){
//自定义结束条件
if("886".equals(line)){
break ;
}
//创建数据报包
DatagramPacket dp = new DatagramPacket(
line.getBytes(),
line.getBytes().length,
InetAddress.getByName("10.12.152.129"),
10010);
ds.send(dp);
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(ds!=null){
ds.close();
}
}
}
}
接收
Udp接收端不断的接收数据,接收端一般不关闭(模拟真实场景)
public class ReceiveDemo {
public static void main(String[] args) throws Exception{
try {
System.out.println("等待接收");
DatagramSocket ds =new DatagramSocket(10010) ;
while(true){
//创建接收端的Socket对象
//创建数据报包:接收容器
DatagramPacket dp = new DatagramPacket(new byte[1024],new byte[1024].length) ;
//接收
ds.receive(dp);
//准备解析真实数据
String str = new String(dp.getData(),0,dp.getLength()) ;
String ip = dp.getAddress().getHostAddress() ;
System.out.println("data from: "+ip+" and content is: "+str );
// ds.close(); //接收端不需要关闭
}
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
使用UDP在一个窗口下聊天
需要两条线程:发送端发消息的线程
接收端接收消息的线程
创建线程的方式:(除过线程池)
1)继承自Thread类
2)实现Runnable接口 ---> 能够多个线程占用的 内存空间(共享共用)
代理----静态代理模式
public class ChatRoom {
public static void main(String[] args) throws Exception{
//创建两端的Socket对象
//发送端:
DatagramSocket ds = new DatagramSocket() ;
//接收端
DatagramSocket ds2 = new DatagramSocket(12306) ;
//创建资源类对象
//发送端的资源类以及接收端端的子类
SendThread st = new SendThread(ds) ;
ReceiveThread rt = new ReceiveThread(ds2) ;
//创建线程对象
Thread t1 = new Thread(st) ;
Thread t2 = new Thread(rt) ;
t1.start();
t2.start();
}
}
//-----------------
//发送资源类
public class SendThread implements Runnable {
private DatagramSocket ds ;
public SendThread(DatagramSocket ds){
this.ds = ds ;
}
@Override
public void run() {
try {
//不断键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in)) ;
String line = null ;
while((line=br.readLine())!=null){
if("over".equals(line)){
break ;
}
//创建数据报包
DatagramPacket dp = new DatagramPacket(line.getBytes(),
line.getBytes().length,
InetAddress.getByName("ip地址"),
12306);
//发送数据
ds.send(dp) ;
}
} catch (Exception e) {
e.printStackTrace();
}finally {
if(ds!=null){
ds.close();
}
}
}
}
//---------------------
//接收端
public class ReceiveThread implements Runnable {
private DatagramSocket ds ;
public ReceiveThread(DatagramSocket ds){
this.ds = ds ;
}
@Override
public void run() {
try {
while(true){
//创建接收端的Socket对象
//创建数据报包:接收容器
DatagramPacket dp = new DatagramPacket(new byte[1024],new byte[1024].length) ;
//接收
ds.receive(dp);
//准备解析真实数据
String str = new String(dp.getData(),0,dp.getLength()) ;
String ip = dp.getAddress().getHostAddress() ;
System.out.println("data from: "+ip+" and content is: "+str );
}
} catch (Exception e) {
e.printStackTrace();
}
//接收不需要关闭
}
}
使用TCP/IP方式发送数据
TCP/IP协议:客户端发送的过程
1)创建客户端的Socket
public Socket(String host,int port) throws UnknownHostException,IOException
2)public OutputStream getOutputStream()throws IOException
获取当前客户端对象所在的通道内的输出流对象
3)使用当前通道内的字节输出流 写数据过去
4)释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
//1)创建客户端的Socket
Socket socket = new Socket("10.12.152.129",6666) ;
//2)获取当前客户端对象所在的通道内的输出流对象
OutputStream outputStream = socket.getOutputStream();
//3)写数据
outputStream.write("hello,TCP,我来了".getBytes());
//4)释放资源
socket.close();
}
}
服务器端
1)创建服务器端的Socket :此类实现服务器套接字
public ServerSocket(int port)
throws IOException
2)监听客户端连接
public Socket accept()
throws IOException
3) 通过监听到的客户端对象 获取通道的输入流
public InputStream getInputStream()
4)关闭资源
服务器端关闭
public class ServerSocketDemo {
public static void main(String[] args) throws IOException {
//创建服务器端的Socket
ServerSocket ss = new ServerSocket(6666) ; //一旦能成功,就立即建立通道
System.out.println("服务器正在等待连接...");
//2)监听并获取客户端的socket对象
Socket socket = ss.accept(); //阻塞式方法 如果没有监听到,一直等
//3)获取通道内的输入流
InputStream inputStream = socket.getInputStream();
//一次读取一个字节数组
byte[] bytes = new byte[1024] ;
int len = inputStream.read(bytes);
String str = new String(bytes,0,len) ;
//通过监听到客户端的socket对象获取ip地址
String ip = socket.getInetAddress().getHostAddress();
System.out.println("data from :" +ip +" content is :"+str);
System.out.println("服务器端接收完毕...");
//释放资源
ss.close();
}
}
Day2.5
什么是反射
什么是反射?
反射就是获取一个类的字节码文件,然后加载该类的所有的成员
成员变量所在类---->Field
成员方法所在类---->Method
构造方法所在类--->Constructor
给成员变量赋值通过Field,调用成员方法Method,通过构造器创建的对象...
//获取一个类的字节码文件对象
//1)Object类的getClass()
Person p = new Person() ;
Class c1 = p.getClass();
System.out.println(c1);
System.out.println(c1.getName());//获取当前Person类的全限定名称com.qf.reflect_01.Person
//----------------------
//2)任意Java类型的class属性
Class c2 = Person.class ;
System.out.println(c2);
System.out.println(c2.getName());
System.out.println(c1==c2);
//----------------
//3)Class的静态功能
Class c3 = Class.forName("com.qf.reflect_01.Person") ;
System.out.println(c3);//class com.qf.reflect_01.Person
通过反射获取一个类的构造器并且创建当前类对象
public class Reflect_getCon {
public static void main(String[] args) throws Exception {
Class clazz = Class.forName("com.qf.reflect_01.Person") ;
Constructor con = clazz.getConstructor() ;
Object obj = con.newInstance();
System.out.println(obj);
//之前写法
Person p = new Person() ;
System.out.println(p);
通过反射获取指定的构造方法(非公共),并创建该类实例
私有的构造方法不能直接new的
public class Reflect_getCon2 {
public static void main(String[] args) throws Exception {
//获取Person类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person");
Constructor con = clazz.getDeclaredConstructor(String.class,int.class) ;
con.setAccessible(true);
访问Person类的默认修饰符的构造方法,并且创建当前类实例
public class Refelect_getCon3 {
public static void main(String[] args) throws Exception {
//获取当期类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person") ;
//获取构造器Constructor
Constructor con = clazz.getDeclaredConstructor(String.class,int.class,String.class) ;
//构造方法:默认修饰符
//取消Java语言访问检查
con.setAccessible(true);
//创建该类实例
Object obj = con.newInstance("高圆圆",41,"鄠邑区") ;
System.out.println(obj);
}
}
通过反射方式获取成员变量Field,并给其进行赋值!
//之前的写法:
//通过无参构造方法创建UI小
//Person person = new Person() ;
//person.setName("高圆圆") ;
//person.setAge(41) ;
public class ReflectDemo {
public static void main(String[] args) throws Exception{
//1)获取指定的类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person") ;
//方式1:通过无参构造器创建实例
//2)通过反射获取单个公共的构造方法,无参
/* Constructor constructor = clazz.getConstructor();
//System.out.println(constructor);
//3)通过构造器创建当前类实例
Object obj = constructor.newInstance();
System.out.println(obj);*/
//方式1:通过无参构造器创建实例
//2)通过反射获取单个公共的构造方法,无参
/* Constructor constructor = clazz.getConstructor();
//System.out.println(constructor);
//3)通过构造器创建当前类实例
Object obj = constructor.newInstance();
System.out.println(obj);*/
//方式2:直接创建当前类实例
//Class类的功能:直接通过当前类的字节码文件对象创建当前类对象
//public T newInstance()
Object obj = clazz.newInstance();
System.out.println(obj);
//获取指定的单个的字段(成员变量):公共字段
//name:公共的字段
//public Field getField(String name):参数名称为"成员变量名称"
Field nameField = clazz.getField("name");
//给当前Field所代表的的指定的字段name来进行赋值
// public void set(Object obj,Object value)
//将指定的值绑定在当前类的实例上
nameField.set(obj,"张三");
System.out.println(obj);
//获取age所在的Field对象,为其赋值
//Field getDeclaredField(String name):获取指定的字段Field
Field ageField = clazz.getDeclaredField("age");
//取消Java语言访问检查
//私有属性
ageField.setAccessible(true);
//赋值
ageField.set(obj,41);
System.out.println(obj);
System.out.println("----------------------------");
Field addressField = clazz.getDeclaredField("address");
addressField.setAccessible(true);
addressField.set(obj,"山西省");
System.out.println(obj);
}
}
反射面试题
现在有一个ArrayList<String>,如何实现给里面存储Integer类型呢?
可以,通过反射方式操作:-----获取Class---->Method--->invoke(当前类实例,方法实际参数)
public class Test {
public static void main(String[] args) throws Exception {
//创建一个ArrayList<String>
ArrayList<String> array = new ArrayList<String>() ;
array.add("hello") ;
array.add("world") ;
array.add("javaee") ;
System.out.println(array);
System.out.println("--------------------");
// array.add(100) ;
//通过反射方式调用add方法
//Object的getClass()获取字节码文件对象
Class clazz = array.getClass() ;
//clazz创建当前类实例
Object obj = clazz.newInstance();//通过反射创建
//获取Method对象:方法名 add
Method addMethod = clazz.getMethod("add", Object.class);
//调用方法
addMethod.invoke(obj,"mysql") ;
addMethod.invoke(obj,100) ;
addMethod.invoke(obj,50) ;
System.out.println(obj);
}
}
通过反射方式来调用Person类中的成员方法(非静态的)
public class ReflectDemo {
public static void main(String[] args) throws Exception{
//获取Person类的字节码文件对象
Class clazz = Class.forName("com.qf.reflect_01.Person");
//无参构造方法创建对象:
Constructor con = clazz.getConstructor();
//创建Person类的实例
Object obj = con.newInstance();
Method showMethod = clazz.getMethod("show");
Object returnObj = showMethod.invoke(obj);
System.out.println(returnObj);
//获取指定的Method
Method functionMethod = clazz.getDeclaredMethod("function", int.class);
//取消Java语言访问检查
functionMethod.setAccessible(true);
Object retunrObj2 = functionMethod.invoke(obj, 27);
System.out.println(retunrObj2);
Method methodM = clazz.getDeclaredMethod("method") ;
methodM.setAccessible(true );
Object returnObj3 = methodM.invoke(obj);
}
}
反射的应用2: Class.forName("全限定名称"):参数为字符串:被经常用在配置文件中
public class Test2 {
public static void main(String[] args) throws IOException, ClassNotFoundException,
IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//创建一个学生类
Student s = new Student() ;
s.love();
//代码不断变化
//工人类
Worker worker = new Worker() ;
worker.love();
System.out.println("-----------------------------------");
InputStream inputStream = Test2.class.getClassLoader().
getResourceAsStream("class.properties");
//创建属性集合列表
Properties prop = new Properties() ;
prop.load(inputStream);
System.out.println(prop);
//通过key获取value
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
//反射获取当前className里面的类的字节码文件对象
Class clazz = Class.forName(className) ;
// System.out.println(clazz);
//直接当前类实例
Object obj = clazz.newInstance();
//反射获取Method对象
Method method = clazz.getMethod(methodName);
method.invoke(obj) ;
}
}
//------------
public class Student {
public void love(){
System.out.println("爱学习,爱Java");
}
}
//------------------
public class Worker {
public void love(){
System.out.println("爱生活,爱敲代码...");
}
}