定时器
定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。
依赖Timer和TimerTask这两个类:
Timer:定时
public Timer() 创建一个定时器对象
public void schedule(TimerTask task,long delay) 在delay延时后执行task任务
public void schedule(TimerTask task,long delay,long period) 任务task在delay延时后开始执行,隔period时间后再次执行
public void cancel() 结束任务
TimerTask:任务
public class TimerDemo {
public static void main(String[] args) {
// 创建定时器对象
Timer t = new Timer();
// 3秒后执行爆炸任务
// t.schedule(new MyTask(), 3000);
//结束任务
t.schedule(new MyTask(t), 3000);
}
}
// 做一个任务
class MyTask extends TimerTask {
private Timer t;
public MyTask(){}
public MyTask(Timer t){
this.t = t;
}
@Override
public void run() {
System.out.println("beng,爆炸了");
t.cancel();
}
}
public class TimerDemo2 {
public static void main(String[] args) {
// 创建定时器对象
Timer t = new Timer();
// 3秒后执行爆炸任务第一次,如果不成功,每隔2秒再继续炸
t.schedule(new MyTask2(), 3000, 2000);
}
}
// 做一个任务
class MyTask2 extends TimerTask {
@Override
public void run() {
System.out.println("beng,爆炸了");
}
}
/*
* 需求:在指定的时间删除我们的指定目录
*/
class DeleteFolder extends TimerTask {
@Override
public void run() {
File srcFolder = new File("demo");
deleteFolder(srcFolder);
}
// 递归删除目录
public void deleteFolder(File srcFolder) {
File[] fileArray = srcFolder.listFiles();
if (fileArray != null) {
for (File file : fileArray) {
if (file.isDirectory()) {
deleteFolder(file);
} else {
System.out.println(file.getName() + ":" + file.delete());
}
}
System.out.println(srcFolder.getName() + ":" + srcFolder.delete());
}
}
}
public class TimerTest {
public static void main(String[] args) throws ParseException {
Timer t = new Timer();
String s = "2022-04-03 15:45:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(s);
t.schedule(new DeleteFolder(), d);
}
}
1:多线程有几种实现方案,分别是哪几种?
两种。
继承Thread类
实现Runnable接口
扩展一种:实现Callable接口。这个得和线程池结合。
2:同步有几种方式,分别是什么?
两种。
同步代码块
同步方法
3:启动一个线程是run()还是start()?它们的区别?
start();
run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
start():启动线程,并由JVM自动调用run()方法
4:sleep()和wait()方法的区别
sleep():必须指时间;不释放锁
wait():可以不指定时间,也可以指定时间;释放锁
5:为什么wait(),notify(),notifyAll()等方法都定义在Object类中
因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
而Object代码任意的对象,所以,定义在这里面
面向对象思想设计原则及常见的设计模式
面向对象设计思想原则
单一职责原则
其实就是开发人员经常说的”高内聚,低耦合”
也就是说,每个类应该只有一个职责,对外只能提供一种功能,而引起类变化的原因应该只有一个。在设计模式中,所有的设计模式都遵循这一原则
开闭原则
核心思想是:一个对象对扩展开放,对修改关闭。
其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码。
也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证它能一直运行下去,如何能够做到这一点呢?这就需要借助于抽象和多态,即把可能变化的内容抽象出来,从而使抽象的部分是相对稳定的,而具体的实现则是可以改变和扩展的。
里氏替换原则
核心思想:在任何父类出现的地方都可以用它的子类来替代。
其实就是说:同一个继承体系中的对象应该有共同的行为特征。
依赖注入原则
核心思想:要依赖于抽象,不要依赖于具体实现。
其实就是说:在应用程序中,所有的类如果使用或依赖于其他的类,则应该依赖这些其他类的抽象类,而不是这些其他类的具体类。为了实现这一原则,就要求我们在编程的时候针对抽象类或者接口编程,而不是针对具体实现编程。
接口分离原则
核心思想:不应该强迫程序依赖它们不需要使用的方法。
其实就是说:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口中。
迪米特原则
核心思想:一个对象应当对其他对象尽可能少的了解
其实就是说:降低各个对象之间的耦合,提高系统的可维护性。在模块之间应该只通过接口编程,而不理会模块的内部工作原理,它可以使各个模块耦合度降到最低,促进软件的复用
设计模式
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
设计模式不是一种方法和技术,而是一种思想
设计模式和具体的语言无关,学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,使设计的程序可复用
学习设计模式能够促进对面向对象思想的理解,反之亦然。它们相辅相成
设计模式的几个要素
名字 必须有一个简单,有意义的名字
问题 描述在何时使用模式
解决方案 描述设计的组成部分以及如何解决问题
效果 描述模式的效果以及优缺点
设计模式的分类
创建型模式 对象的创建
结构型模式 对象的组成(结构)
行为型模式 对象的行为
创建型模式:简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。(6个)
结构型模式:外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。(7个)
行为型模式:模版方法模式、观察者模式、状态模式、职责链模式、命令模式、访问者模式、策略模式、备忘录模式、迭代器模式、解释器模式。(10个)
简单工厂模式概述
又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
优点
客户端不需要在负责对象的创建,从而明确了各个类的职责
缺点
这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护
//动物类
public abstract class Animal {
public abstract void eat();
}
//动物工厂类
public class AnimalFactory {
private AnimalFactory() {
}
// public static Dog createDog() {
// return new Dog();
// }
//
// public static Cat createCat() {
// return new Cat();
// }
public static Animal createAnimal(String type) {
if ("dog".equals(type)) {
return new Dog();
} else if ("cat".equals(type)) {
return new Cat();
} else {
return null;
}
}
}
//测试类
public class AnimalDemo {
public static void main(String[] args) {
// 具体类调用没写
Dog d = new Dog();
d.eat();
Cat c = new Cat();
c.eat();
System.out.println("------------");
// 工厂有了后,通过工厂给造
// Dog dd = AnimalFactory.createDog();
// Cat cc = AnimalFactory.createCat();
// dd.eat();
// cc.eat();
// System.out.println("------------");
// 工厂改进后
Animal a = AnimalFactory.createAnimal("dog");
a.eat();
a = AnimalFactory.createAnimal("cat");
a.eat();
// NullPointerException
a = AnimalFactory.createAnimal("pig");
if (a != null) {
a.eat();
} else {
System.out.println("对不起,暂时不提供这种动物");
}
}
}
工厂方法模式概述
工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
优点
客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性
缺点
需要额外的编写代码,增加了工作量
public abstract class Animal {
public abstract void eat();
}
public class DogFactory implements Factory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
public class DogFactory implements Factory {
@Override
public Animal createAnimal() {
return new Dog();
}
}
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
public class CatFactory implements Factory {
@Override
public Animal createAnimal() {
return new Cat();
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
public class AnimalDemo {
public static void main(String[] args) {
// 需求:我要狗
Factory f = new DogFactory();
Animal a = f.createAnimal();
a.eat();
System.out.println("-------");
//需求:我要猫
f = new CatFactory();
a = f.createAnimal();
a.eat();
}
}
单例设计模式概述
单例模式就是要确保类在内存中只有一个对象,该实例必须自动创建,并且对外提供。
优点
在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
缺点
没有抽象层,因此扩展很难。
职责过重,在一定程序上违背了单一职责
单例模式饿汉式类,类一加载就创建,保证类在内存中只有一个对象
如何保证类在内存中只有一个对象
把构造方法私有
在成员位置自己创建一个对象
通过一个公共的方法提供访问
public class Student {
// 构造私有
private Student() {
}
// 自己造一个
// 静态方法只能访问静态成员变量,加静态
// 为了不让外界直接访问修改这个值,加private
private static Student s = new Student();
// 提供公共的访问方式
// 为了保证外界能够直接使用该方法,加静态
public static Student getStudent() {
return s;
}
}
public class StudentDemo {
public static void main(String[] args) {
// Student s1 = new Student();
// Student s2 = new Student();
// System.out.println(s1 == s2); // false
// 通过单例如何得到对象呢?
// Student.s = null;
Student s1 = Student.getStudent();
Student s2 = Student.getStudent();
System.out.println(s1 == s2);
System.out.println(s1); // null,cn.itcast_03.Student@175078b
System.out.println(s2);// null,cn.itcast_03.Student@175078b
}
}
单例模式懒汉式,用的时候,才去创建对象
面试题:单例模式的思想是什么?请写一个代码体现。
开发:饿汉式(是不会出问题的单例模式)
面试:懒汉式(可能会出问题的单例模式)
懒加载(延迟加载)
线程安全问题
是否多线程环境 是
是否有共享数据 是
是否有多条语句操作共享数据 是
public class Teacher {
private Teacher() {
}
private static Teacher t = null;
public synchronized static Teacher getTeacher() {
// t1,t2,t3
if (t == null) {
//t1,t2,t3
t = new Teacher();
}
return t;
}
}
public class TeacherDemo {
public static void main(String[] args) {
Teacher t1 = Teacher.getTeacher();
Teacher t2 = Teacher.getTeacher();
System.out.println(t1 == t2);
System.out.println(t1); // cn.itcast_03.Teacher@175078b
System.out.println(t2);// cn.itcast_03.Teacher@175078b
}
}
Day25
GUI
Graphical User Interface(图形用户接口)
用图形的方式,来显示计算机操作的界面,这样更方便更直观
方法
构造方法
Frame():创建一个不可见的窗体
Frame f = new Frame();
Frame(String title):创建一个带标题的不可见窗体
Frame f = new Frame(Hello,世界);
设置窗口可见
f.show();//已过时
f.setVisible(true);//true代表可见,false代表不可见
设置窗体标题
f.setTitle("HelloWorld");
等同于带参构造,同时出现时会更改带参构造的标题名
设置窗体大小
直接设置:f.setSize(400, 300); //单位:像素
借助Dimension类:Dimension(int width, int height)
Dimension d = new Dimension(400, 300); f.setSize(d);
设置窗体位置
直接设置:f.setLocation(400, 200);//单位:像素
借助Point类:Point(int x, int y)
Point p = new Point(400, 200); f.setLocation(p);
一个方法设置窗体大小和位置
f.setBounds(x,y,width,height);
f.setBounds(400,200,400,300);
事件监听机制
事件源 事件发生的地方
事件 就是要发生的事情
事件处理 就是针对发生的事情做出的处理方案
事件监听 就是把事件源和事件关联起来
举例:人受伤事件
事件源:人(具体的对象)
Person p1 = new Person("张三");
Person p2 = new Person("李四");
事件:受伤
interface 受伤接口 {
一拳();
一板砖();
}
事件处理:
受伤处理类 implements 受伤接口 {
一拳(){ System.out.println("鼻子流血了,送到卫生间洗洗"); }
一板砖(){ System.out.println("头破血流,送到太平间"); }
}
事件监听:
p1.注册监听(受伤接口)
关闭窗口
f.addWindowListener(new WindowListener(){重写这个匿名内部类的所有方法,(可以空实现),将windowClosing(WindowEvent e) 方法为System.exit(0);});
适配器改进
f.addWindowListener(new WindowAdapter() { 重写这个适配器类的windowClosing方法为System.exit(0);});
创建按钮
Button bu = new Button();
创建并设置名字
Button bu = new Button("按钮");
把按钮添加到窗体
f.add(bu);
f.add();可以添加任意组件,按钮,文本框,文本域等
** 设置布局为流式布局**
f.setLayout(new FlowLayout());
对按钮添加事件
bu.addActionListener(new ActionListener() {重写actionPerformed方法});
创建文本框
TextField tf = new TextField();
默认
带一个int数值表示文本框可以放多少个字符
带一个String的字符串,就是默认出来的字符串
带一个String和int数值,表示默认字符串以及可以放多少个字符
创建文本域
TextArea ta = new TextArea();
带两个Int数值表示多少行多少列
获取文本框的值
String tf_str = tf.getText().trim(); trim()时不允许有空格
设置文本框的值
tf.setText("");
为空是清空文本框
设置文本域的值
ta.setText(tf_str);
追加设置文本域的值
ta.append(tf_str + "\r\n"); \r\n表示换行
获取光标
tf.requestFocus();
表示将光标的值给调用者tf
设置背景色
f.setBackground(Color.RED);
Color.可选很多颜色
鼠标事件
void mouseClicked(MouseEvent e) 单击并释放
mouseEntered(MouseEvent e) 进入
mouseExited(MouseEvent e) 离开
void mousePressed(MouseEvent e)鼠标按键在组件上按下时调用
void mouseReleased(MouseEvent e)鼠标按钮在组件上释放时调用
对按钮添加鼠标事件
Button redbutton = new Button("红色");
redbutton.addMouseListener(new MouseAdapter() {重写鼠标事件的方法 });
创建标签对象
Label label = new Label("可以输入文字");
键盘事件
keyPressed(KeyEvent e) 摁下某个键时调用
keyReleased(KeyEvent e) 释放某个键时调用此方法
keyTyped(KeyEvent e) 键入某个键时调用此方法
获取每次键入的值
方法:char getKeyChar()
举例:char ch = e.getKeyChar();
取消键盘事件
e.consume();
菜单
创建菜单栏
MenuBar mb = new MenuBar();
创建菜单
Menu m = new Menu("文件");
创建菜单项
MenuItem mi = new MenuItem("退出系统");
先创建菜单栏,在创建菜单,最后才是菜单项,菜单中可以添加菜单,作为子菜单
注意添加的顺序,从小到大依次添加
将菜单栏添加到窗体(为窗体设置菜单栏)
f.setMenuBar(mb);
对菜单项添加事件
mi.addActionListener(new ActionListener() {重写actionPerformed方法,实现点击时执行相应的功能});
Day26
网络编程三要素
IP地址
端口
协议
端口号:正在运行的程序的标识,有效端口:065535,其中01024系统使用或保留端口
协议:通信的规则
UDP:
把数据打包
数据有限制(64k)
不建立连接
速度快
不可靠
TCP:
建立连接通道
数据无限制
速度慢
可靠
InetAddress
public static InetAddress getByName(String host):根据主机名或者IP地址的字符串表示得到IP地址对象
public String getHostName()获取主机名
public String getHostAddress()获取IP地址
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
// public static InetAddress getByName(String host)
// InetAddress address = InetAddress.getByName("zhangsan");
// InetAddress address = InetAddress.getByName("192.168.12.92");
InetAddress address = InetAddress.getByName("192.168.12.63");
// 获取两个东西:主机名,IP地址
// public String getHostName()
String name = address.getHostName();
// public String getHostAddress()
String ip = address.getHostAddress();
System.out.println(name + "---" + ip);
}
}
Socket
网络套接字,网络编程,套接字编程
Socket包含IP地址和端口号
Socket原理机制
通信的两端都有Socket
网络通信就是Socket之间的通信
数据在两个Socket之间用IO流传输
UDP协议发送数据:
创建发送端Socket对象(DatagramSocket无参构造)
创建数据,并把数据打包(DatagramPacket(byte[] buf, int length, InetAddress address, int port))数据,长度,IP地址,端口号
调用Socket对象的发送方法发送数据包
释放资源(底层为IO流传输)
UDP协议接收数据:
创建接收端Socket对象(DatagramSocket(int port)指定接受的端口号)
创建一个数据包(接收容器DatagramPacket(byte[] buf, int length)只需要存储的地方和长度)
调用Socket对象的接收方法接收数据(public void receive(DatagramPacket p)接收数据)
解析数据包,并显示在控制台
释放资源
public byte[] getData():获取数据缓冲区
public int getLength():获取数据的实际长度
//发送
public class SendDemo {
public static void main(String[] args) throws IOException {
// 创建发送端Socket对象
// DatagramSocket()
DatagramSocket ds = new DatagramSocket();
// 创建数据,并把数据打包
// DatagramPacket(byte[] buf, int length, InetAddress address, int port)
// 创建数据
byte[] bys = "hello,udp,我来了".getBytes();
// 长度
int length = bys.length;
// IP地址对象
InetAddress address = InetAddress.getByName("192.168.12.92");
// 端口
int port = 10086;
DatagramPacket dp = new DatagramPacket(bys, length, address, port);
// 调用Socket对象的发送方法发送数据包
// public void send(DatagramPacket p)
ds.send(dp);
// 释放资源
ds.close();
}
}
//接受
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
// 创建接收端Socket对象
// DatagramSocket(int port)
DatagramSocket ds = new DatagramSocket(10086);
// 创建一个数据包(接收容器)
// DatagramPacket(byte[] buf, int length)
byte[] bys = new byte[1024];
int length = bys.length;
DatagramPacket dp = new DatagramPacket(bys, length);
// 调用Socket对象的接收方法接收数据
// public void receive(DatagramPacket p)
ds.receive(dp); // 阻塞式
// 解析数据包,并显示在控制台
// 获取对方的ip
// public InetAddress getAddress()
InetAddress address = dp.getAddress();
String ip = address.getHostAddress();
// public byte[] getData():获取数据缓冲区
// public int getLength():获取数据的实际长度
byte[] bys2 = dp.getData();
int len = dp.getLength();
String s = new String(bys2, 0, len);
System.out.println(ip + "传递的数据是:" + s);
// 释放资源
ds.close();
}
}
对上列代码进行优化
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
// 创建接收端的Socket对象
DatagramSocket ds = new DatagramSocket(12345);
// 创建一个包裹
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
// 接收数据
ds.receive(dp);
// 解析数据
String ip = dp.getAddress().getHostAddress();
String s = new String(dp.getData(), 0, dp.getLength());
System.out.println("from " + ip + " data is : " + s);
// 释放资源
ds.close();
}
}
public class SendDemo {
public static void main(String[] args) throws IOException {
// 创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket();
// 创建数据并打包
byte[] bys = "helloworld".getBytes();
DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.12.92"), 12345);
// 发送数据
ds.send(dp);
// 释放资源
ds.close();
}
}
键盘录入数据发送,只到输入886结束
public class ReceiveDemo {
public static void main(String[] args) throws IOException {
// 创建接收端的Socket对象
DatagramSocket ds = new DatagramSocket(12345);
while (true) {
// 创建一个包裹
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
// 接收数据
ds.receive(dp);
// 解析数据
String ip = dp.getAddress().getHostAddress();
String s = new String(dp.getData(), 0, dp.getLength());
System.out.println("from " + ip + " data is : " + s);
}
// 释放资源
// 接收端应该一直开着等待接收数据,是不需要关闭
// ds.close();
}
}
public class SendDemo {
public static void main(String[] args) throws IOException {
// 创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket();
// 封装键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while ((line = br.readLine()) != null) {
if ("886".equals(line)) {
break;
}
// 创建数据并打包
byte[] bys = line.getBytes();
// DatagramPacket dp = new DatagramPacket(bys, bys.length,
// InetAddress.getByName("192.168.12.92"), 12345);
DatagramPacket dp = new DatagramPacket(bys, bys.length,
InetAddress.getByName("192.168.12.255"), 12345);
// 发送数据
ds.send(dp);
}
// 释放资源
ds.close();
}
}
用多线程改进
public class ReceiveThread implements Runnable {
private DatagramSocket ds;
public ReceiveThread(DatagramSocket ds) {
this.ds = ds;
}
@Override
public void run() {
try {
while (true) {
// 创建一个包裹
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
// 接收数据
ds.receive(dp);
// 解析数据
String ip = dp.getAddress().getHostAddress();
String s = new String(dp.getData(), 0, dp.getLength());
System.out.println("from " + ip + " data is : " + s);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
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 ("886".equals(line)) {
break;
}
// 创建数据并打包
byte[] bys = line.getBytes();
// DatagramPacket dp = new DatagramPacket(bys, bys.length,
// InetAddress.getByName("192.168.12.92"), 12345);
DatagramPacket dp = new DatagramPacket(bys, bys.length,InetAddress.getByName("192.168.12.255"), 12306);
// 发送数据
ds.send(dp);
}
// 释放资源
ds.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ChatRoom {
public static void main(String[] args) throws IOException {
DatagramSocket dsSend = new DatagramSocket();
DatagramSocket dsReceive = new DatagramSocket(12306);
SendThread st = new SendThread(dsSend);
ReceiveThread rt = new ReceiveThread(dsReceive);
Thread t1 = new Thread(st);
Thread t2 = new Thread(rt);
t1.start();
t2.start();
}
}
TCP协议发送数据:
创建发送端的Socket对象(Socket(String host, int port))
这一步如果成功,就说明连接已经建立成功了
获取输出流,写数据(public OutputStream getOutputStream())
释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 创建发送端的Socket对象
// Socket(InetAddress address, int port)
// Socket(String host, int port)
// Socket s = new Socket(InetAddress.getByName("192.168.12.92"), 8888);
Socket s = new Socket("192.168.12.92", 8888);
// 获取输出流,写数据
// public OutputStream getOutputStream()
OutputStream os = s.getOutputStream();
os.write("hello,tcp,我来了".getBytes());
// 释放资源
s.close();
}
}
TCP协议接收数据:
创建接收端的Socket对象(ServerSocket(int port))
监听客户端连接。返回一个对应的Socket对象(public Socket accept())
获取输入流,读取数据显示在控制台
释放资源
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 创建发送端的Socket对象
// Socket(InetAddress address, int port)
// Socket(String host, int port)
// Socket s = new Socket(InetAddress.getByName("192.168.12.92"), 8888);
Socket s = new Socket("192.168.12.92", 8888);
// 获取输出流,写数据
// public OutputStream getOutputStream()
OutputStream os = s.getOutputStream();
os.write("hello,tcp,我来了".getBytes());
// 释放资源
s.close();
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 创建接收端的Socket对象
// ServerSocket(int port)
ServerSocket ss = new ServerSocket(8888);
// 监听客户端连接。返回一个对应的Socket对象
// public Socket accept()
Socket s = ss.accept(); // 侦听并接受到此套接字的连接。此方法在连接传入之前一直阻塞。
// 获取输入流,读取数据显示在控制台
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys); // 阻塞式方法
String str = new String(bys, 0, len);
String ip = s.getInetAddress().getHostAddress();
System.out.println(ip + "---" + str);
// 释放资源
s.close();
// ss.close(); //这个不应该关闭
}
}
加入消息反馈
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(9999);
// 监听客户端的连接
Socket s = ss.accept(); // 阻塞
// 获取输入流
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys); // 阻塞
String server = new String(bys, 0, len);
System.out.println("server:" + server);
// 获取输出流
OutputStream os = s.getOutputStream();
os.write("数据已经收到".getBytes());
// 释放资源
s.close();
// ss.close();
}
}
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 9999);
// 获取输出流
OutputStream os = s.getOutputStream();
os.write("今天天气很好,适合睡觉".getBytes());
// 获取输入流
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);// 阻塞
String client = new String(bys, 0, len);
System.out.println("client:" + client);
// 释放资源
s.close();
}
}
键盘输入并传输,服务器打印在控制台
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(22222);
// 监听客户端连接
Socket s = ss.accept();
// 包装通道内容的流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
// br.close();
s.close();
// ss.close();
}
}
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 22222);
// 键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 把通道内的流给包装一下
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) {
// 键盘录入数据要自定义结束标记
if ("886".equals(line)) {
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
// 释放资源
// bw.close();
// br.close();
s.close();
}
}
客户端键盘录入,服务器输出文本文件
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 23456);
// 封装键盘录入
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// 封装通道内的数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) {
if ("over".equals(line)) {
break;
}
bw.write(line);
bw.newLine();
bw.flush();
}
// bw.close();
// br.close();
s.close();
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(23456);
// 监听客户端连接
Socket s = ss.accept();
// 封装通道内的数据
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
// 封装文本文件
BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
// br.close();
s.close();
// ss.close();
}
}
客户端文本文件,服务器输出到控制台
public class ClientDemo {
public static void main(String[] args) throws IOException {
// 创建Socket对象
Socket s = new Socket("192.168.12.92", 34567);
// 封装文本文件
BufferedReader br = new BufferedReader(new FileReader("InetAddressDemo.java"));
// 封装通道内的流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
br.close();
s.close();
}
}
public class ServerDemo {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(34567);
// 监听客户端连接
Socket s = ss.accept();
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
s.close();
}
}
客户端上传文本文件到客户端
public class UploadClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 11111);
// 封装文本文件
BufferedReader br = new BufferedReader(new FileReader("InetAddressDemo.java"));
// 封装通道内流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
// 释放资源
br.close();
s.close();
}
}
public class UploadServer {
public static void main(String[] args) throws IOException {
// 创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(11111);
// 监听客户端连接
Socket s = ss.accept();
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
// 封装文本文件
BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
s.close();
}
}
tcp上传文件服务器给出反馈
按照我们正常的思路加入反馈信息,结果却没反应,为什么呢?
读取文本文件是可以以null作为结束信息的,但是呢,通道内是不能这样结束信息的所以,服务器根本就不知道你结束了。而你还想服务器给你反馈。所以,就相互等待了
如何解决呢
在多写一条数据,告诉服务器,读取到这条数据说明我就结束,你也结束吧
这样做可以解决问题,但是不好
Socket对象提供了一种解决方案
public void shutdownOutput()
public class UploadClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 11111);
// 封装文本文件
BufferedReader br = new BufferedReader(new FileReader(
"InetAddressDemo.java"));
// 封装通道内流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
//自定义一个结束标记
// bw.write("over");
// bw.newLine();
// bw.flush();
//Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了
s.shutdownOutput();
// 接收反馈
BufferedReader brClient = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String client = brClient.readLine(); // 阻塞
System.out.println(client);
// 释放资源
br.close();
s.close();
}
}
public class UploadServer {
public static void main(String[] args) throws IOException {
// 创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(11111);
// 监听客户端连接
Socket s = ss.accept();// 阻塞
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 封装文本文件
BufferedWriter bw = new BufferedWriter(new FileWriter("Copy.java"));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
// if("over".equals(line)){
// break;
// }
bw.write(line);
bw.newLine();
bw.flush();
}
// 给出反馈
BufferedWriter bwServer = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
// 释放资源
bw.close();
s.close();
}
}
上传图片并反馈
public class UploadClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 19191);
// 封装图片文件
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("美女.jpg"));
// 封装通道内的流
BufferedOutputStream bos = newBufferedOutputStream(s.getOutputStream());
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
bos.flush();
}
s.shutdownOutput();
// 读取反馈
InputStream is = s.getInputStream();
byte[] bys2 = new byte[1024];
int len2 = is.read(bys2);
String client = new String(bys2, 0, len2);
System.out.println(client);
// 释放资源
bis.close();
s.close();
}
}
public class UploadServer {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(19191);
// 监听客户端连接
Socket s = ss.accept();
// 封装通道内流
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
// 封装图片文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("mn.jpg"));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
bos.flush();
}
// 给一个反馈
OutputStream os = s.getOutputStream();
os.write("图片上传成功".getBytes());
bos.close();
s.close();
}
}
多客户端上传服务器案例多线程
public class UserThread implements Runnable {
private Socket s;
public UserThread(Socket s) {
this.s = s;
}
@Override
public void run() {
try {
// 封装通道内的流
BufferedReader br = new BufferedReader(new InputStreamReader(
s.getInputStream()));
// 封装文本文件
// BufferedWriter bw = new BufferedWriter(new
// FileWriter("Copy.java"));
// 为了防止名称冲突
String newName = System.currentTimeMillis() + ".java";
BufferedWriter bw = new BufferedWriter(new FileWriter(newName));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
// 给出反馈
BufferedWriter bwServer = new BufferedWriter(
new OutputStreamWriter(s.getOutputStream()));
bwServer.write("文件上传成功");
bwServer.newLine();
bwServer.flush();
// 释放资源
bw.close();
s.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class UploadClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket对象
Socket s = new Socket("192.168.12.92", 11111);
// 封装文本文件
// BufferedReader br = new BufferedReader(new FileReader(
// "InetAddressDemo.java"));
BufferedReader br = new BufferedReader(new FileReader(
"ReceiveDemo.java"));
// 封装通道内流
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(
s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) { // 阻塞
bw.write(line);
bw.newLine();
bw.flush();
}
// Socket提供了一个终止,它会通知服务器你别等了,我没有数据过来了
s.shutdownOutput();
// 接收反馈
BufferedReader brClient = new BufferedReader(new InputStreamReader(
s.getInputStream()));
String client = brClient.readLine(); // 阻塞
System.out.println(client);
// 释放资源
br.close();
s.close();
}
}
public class UploadServer {
public static void main(String[] args) throws IOException {
// 创建服务器Socket对象
ServerSocket ss = new ServerSocket(11111);
while (true) {
Socket s = ss.accept();
new Thread(new UserThread(s)).start();
}
}
}
Day27
反射
就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法
使用一个类的功能之前的做法:
Person p = new Person();
p.使用
要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象
Class类:
成员变量 Field
构造方法 Constructor
成员方法 Method
获取class(字节码)文件对象的方式:
Object类的getClass()方法
数据类型的静态属性class
Class类中的静态方法
public static Class forName(String className) 必须是带包的路径,开发中推荐使用这个
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 方式1
Person p = new Person();
Class c = p.getClass();
Person p2 = new Person();
Class c2 = p2.getClass();
System.out.println(p == p2);// false
System.out.println(c == c2);// true
// 方式2
Class c3 = Person.class;
// int.class;
// String.class;
System.out.println(c == c3);
// 方式3
// ClassNotFoundException
Class c4 = Class.forName("a.b.Person");
System.out.println(c == c4);
}
}
获取构造方法
public Constructor[] getConstructors():所有公共构造方法
public Constructor[] getDeclaredConstructors():所有构造方法
获取单个构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes)
参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象
public T newInstance(Object... initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
//通过反射获取构造方法并使用
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("a.b.Person");
// 获取构造方法
// public Constructor[] getConstructors():所有公共构造方法
// public Constructor[] getDeclaredConstructors():所有构造方法
// Constructor[] cons = c.getDeclaredConstructors();
// for (Constructor con : cons) {
// System.out.println(con);
// }
// 获取单个构造方法
// public Constructor<T> getConstructor(Class<?>... parameterTypes)
// 参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象
Constructor con = c.getConstructor();// 返回的是构造方法对象
// Person p = new Person();
// System.out.println(p);
// public T newInstance(Object... initargs)
// 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
Object obj = con.newInstance();
System.out.println(obj);
// Person p = (Person)obj;
// p.show();
}
}
获取带参构造
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("a.b.Person");
// 获取带参构造方法对象
// public Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor con = c.getConstructor(String.class, int.class,String.class);
// 通过带参构造方法对象创建对象
// public T newInstance(Object... initargs)
Object obj = con.newInstance("张三", 18, "北京");
System.out.println(obj);
}
}
通过反射获取私有构造方法并使用
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
// 获取私有构造方法对象
// NoSuchMethodException:每个这个方法异常
// 原因是一开始我们使用的方法只能获取公共的,下面这种方式就可以了。
Constructor con = c.getDeclaredConstructor(String.class);
// 用该私有构造方法创建对象
// IllegalAccessException:非法的访问异常。
// 暴力访问
con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。
Object obj = con.newInstance("张三");
System.out.println(obj);
}
}
通过反射获取成员变量并使用
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
// 获取所有的成员变量
// Field[] fields = c.getFields();公共的
// Field[] fields = c.getDeclaredFields();所有的,包括私有
// for (Field field : fields) {
// System.out.println(field);
// }
/*
* Person p = new Person(); p.address = "北京"; System.out.println(p);
*/
// 通过无参构造方法创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();
System.out.println(obj);
// 获取单个的成员变量
// 获取address并对其赋值
Field addressField = c.getField("address");
// public void set(Object obj,Object value)
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"
System.out.println(obj);
// 获取name并对其赋值
// NoSuchFieldException
Field nameField = c.getDeclaredField("name");
// IllegalAccessException
nameField.setAccessible(true);
nameField.set(obj, "张三");
System.out.println(obj);
// 获取age并对其赋值
Field ageField = c.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(obj, 27);
System.out.println(obj);
}
}
通过反射获取成员方法并使用
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");
// 获取所有的方法
// Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法
// Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法
// for (Method method : methods) {
// System.out.println(method);
// }
Constructor con = c.getConstructor();
Object obj = con.newInstance();
/*
* Person p = new Person(); p.show();
*/
// 获取单个方法并使用
// public void show()
// public Method getMethod(String name,Class<?>... parameterTypes)
// 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型
Method m1 = c.getMethod("show");
// obj.m1(); // 错误
// public Object invoke(Object obj,Object... args)
// 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数
m1.invoke(obj); // 调用obj对象的m1方法
System.out.println("----------");
// public void method(String s)
Method m2 = c.getMethod("method", String.class);
m2.invoke(obj, "hello");
System.out.println("----------");
// public String getString(String s, int i)
Method m3 = c.getMethod("getString", String.class, int.class);
Object objString = m3.invoke(obj, "hello", 100);
System.out.println(objString);
// String s = (String)m3.invoke(obj, "hello",100);
// System.out.println(s);
System.out.println("----------");
// private void function()
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);
m4.invoke(obj);
}
}
反射的应用
通过配置文件运行类中的方法
反射:
需要有配置文件配合使用,用class.txt代替
并且你知道有两个键
className
methodName
//假设有学生类,老师类,工人类,每个类都有一个方法love();实现不同的功能
public class Test {
public static void main(String[] args) throws Exception {
// 反射前的做法,每个类都要创建对象,在调用方法,假设根据需求每次更换一个类执行,就很麻烦
// Student s = new Student();
// s.love();
// Teacher t = new Teacher();
// t.love();
// Worker w = new Worker();
// w.love();
// 反射后的做法
// 加载键值对数据
Properties prop = new Properties();
FileReader fr = new FileReader("class.txt");//根据Class.txt里边的键值对,决定是哪个类,执行那个方法,需求变了需要换类换方法,只需要更改Class.txt里边的
prop.load(fr);
fr.close();
// 获取数据
String className = prop.getProperty("className");
String methodName = prop.getProperty("methodName");
// 反射
Class c = Class.forName(className);
Constructor con = c.getConstructor();
Object obj = con.newInstance();
// 调用方法
Method m = c.getMethod(methodName);
m.invoke(obj);
}
}
/*
* 我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
*/
public class ArrayListDemo {
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
// 创建集合对象
ArrayList<Integer> array = new ArrayList<Integer>();
// array.add("hello");
// array.add(10);
Class c = array.getClass(); // 集合ArrayList的class文件对象
Method m = c.getMethod("add", Object.class);
m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello
m.invoke(array, "world");
m.invoke(array, "java");
System.out.println(array);
}
}
修改任意类的任意成员变量所对应的值
public class Tool {
public void setProperty(Object obj, String propertyName, Object value)
throws NoSuchFieldException, SecurityException,
IllegalArgumentException, IllegalAccessException {
// 根据对象获取字节码文件对象
Class c = obj.getClass();
// 获取该对象的propertyName成员变量
Field field = c.getDeclaredField(propertyName);
// 取消访问检查
field.setAccessible(true);
// 给对象的成员变量赋值为指定的值
field.set(obj, value);
}
}
public class ToolDemo {
public static void main(String[] args) throws NoSuchFieldException,
SecurityException, IllegalArgumentException, IllegalAccessException {
Person p = new Person();
Tool t = new Tool();
t.setProperty(p, "name", "张三");
t.setProperty(p, "age", 27);
System.out.println(p);
System.out.println("-----------");
Dog d = new Dog();
t.setProperty(d, "sex", '男');
t.setProperty(d, "price", 12.34f);
System.out.println(d);
}
}
class Dog {
char sex;
float price;
@Override
public String toString() {
return sex + "---" + price;
}
}
class Person {
private String name;
public int age;
@Override
public String toString() {
return name + "---" + age;
}
}