List item
目录
一、设计模式
1、单例
1)StudentDemo
package com.shujia.lhw.day26.shejimoshi.danli;
/*
创建型的第一种:
单例模式:保证内存中只有一个对象
如何保证一个类在内存中只允许一个对象存在呢?
1、将构造方法私有化
2、在类的成员变量的位置上创建一个对象
3、提供一个公共的静态方法让外界获取到这个对象
通过我们实现后发现,随着类的加载,对象就创建好了,这样的单例模式叫做饿汉式。
*/
public class StudentDemo {
public static void main(String[] args) {
Student s1 = Student.getStudent();
Student s2 = Student.getStudent();
System.out.println(s1 == s2);
System.out.println(s1);
System.out.println(s2);
}
}
package com.shujia.lhw.day26.shejimoshi.danli;
public class Student {
private static Student student= new Student();
private Student(){}
public static Student getStudent(){
return student;
}
}
2)TeacherDemo
package com.shujia.lhw.day26.shejimoshi.danli;
/*
如何保证一个类在内存中只允许一个对象存在呢?
1、将构造方法私有化
2、在类的成员变量的位置上创建一个对象
3、提供一个公共的静态方法让外界获取到这个对象
饿汉式:类一加载,就创建对象
懒汉式:用的时候,再去创建对象,但是内存中始终只有一个对象
1、懒加载(延迟加载)
2、容易产生线程安全问题
1)在存在多线程环境中,只允许出现一个对象的类是共享数据
2)并且有多条语句操作着共享数据
3)需要使用锁来解决线程安全问题
开发使用饿汉模式
面试详细说懒汉式,懒汉式牵扯到线程安全问题
*/
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);
System.out.println(t2);
}
}
package com.shujia.lhw.day26.shejimoshi.danli;
public class Teacher {
private Teacher(){
}
private static Teacher t = null;
//假设现在有3个线程,t1,t2,t3
// public static Teacher getTeacher(){
// synchronized(Teacher.class){
// if(t == null){
// //t1,t2,t3
// t = new Teacher();
// }
// return t;
// }
// }
//静态的同步方法
public synchronized static Teacher getTeacher(){
if (t == null){
//t1,t2,t3
t = new Teacher();
}
return t;
}
}
2、简单工厂模式
1)AnimalDemo
package com.shujia.lhw.day26.shejimoshi.easyfactory;
/*
简单工厂模式(静态工厂方法模式)
优点:
客户端不需要负责创建对象,从而明确了各个类的职责
缺点:
我们定义的静态工厂类负责对象的创建,如果有新的对象增加
获取某些对象的创建方式不同,就需要不断地去修改工厂类,不利于后期维护
*/
public class AnimalDemo {
public static void main(String[] args) {
// Dog dog = new Dog();
// dog.eat();
// Cat cat = new Cat();
// cat.eat();
//通过动物工厂来获取对应的动物
// Dog dog = AnimalFactory.createDog();
// Cat cat = AnimalFactory.createCat();
// dog.eat;
// cat.eat;
//将来我们还想获取熊猫,老虎等动物的时候,就要去修改AnimalFactory工厂类,但是呢,一般情况下,工厂类不允许被修改
Animal dog = AnimalFactory.createAnimal("Dog");
Animal cat = AnimalFactory.createAnimal("Cat");
if (dog!=null){
dog.eat();
}
if (cat!=null){
cat.eat();
}
Animal pig = AnimalFactory.createAnimal("Pig");
if (pig!=null){
pig.eat();
}
}
}
package com.shujia.lhw.day26.shejimoshi.easyfactory;
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 ("Cat".equals(type)){
return new Cat();
}else if("Dog".equals(type)){
return new Dog();
}else{
System.out.println("该工厂不支持创建"+type+"类型的动物");
return null;
}
}
}
package com.shujia.lhw.day26.shejimoshi.easyfactory;
public abstract class Animal {
//吃
public abstract void eat();
}
package com.shujia.lhw.day26.shejimoshi.easyfactory;
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("🐱吃🐟");
}
}
package com.shujia.lhw.day26.shejimoshi.easyfactory;
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("🐕吃🥩");
}
}
3、工厂模式的优点
package com.shujia.lhw.day26.shejimoshi.factoryFunction;
/*
工厂方法模式的优缺点:
优点:
客户端不需要负责对象的创建,从而明确各个类的职责
如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可
不影响其他的代码,后期容易维护,增强了系统的扩展性
缺点:
需要额外的写代码,增加了工作量
*/
public class AnimalDemo {
public static void main(String[] args) {
//我只想要狗
DogFactory dogFactory = new DogFactory();
Animal dog = dogFactory.createAnimal();
dog.eat();
//我想要只猫
CatFactory catFactory = new CatFactory();
Animal cat = catFactory.createAnimal();
cat.eat();
//我想要只猪
PigFactory pigFactory = new PigFactory();
Animal pig = pigFactory.createAnimal();
pig.eat();
}
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;
public abstract class Animal {
public abstract void eat();
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("🐱吃🐟");
}
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;
public class CatFactory implements Factory{
@Override
public Animal createAnimal() {
return new Cat();
}
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("🐕吃🥩");
}
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;
public class DogFactory implements Factory{
@Override
public Animal createAnimal() {
return new Dog();
}
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;
public interface Factory {
public abstract Animal createAnimal();
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;
public class Pig extends Animal{
@Override
public void eat() {
System.out.println("🐖吃饲料");
}
}
package com.shujia.lhw.day26.shejimoshi.factoryFunction;
public class PigFactory implements Factory{
@Override
public Animal createAnimal() {
return new Pig();
}
}
4、设计模式总结
设计模式
经验的总结
1、创建型 创建对象
2、结构型 对象的组成
3、行为型 对象的功能
创建型模式:
1、单例模式
指的是在程序运行的过程中,内存只允许一个对象存在
饿汉式
懒汉式
2、简单工厂模式
3、工厂方法模式
二、网络编程
1、网络编程的三要素
网络编程的三要素:
1、IP地址
2、端口号
3、协议
举例:
假设某同学看上了一个女生,想要去表白。
1、要去找这个女生 ---IP地址
2、对Ta表白,跟Ta说话,对着耳朵说话 ---端口号
3、要说什么呢?"I Love You"
但是呢,这个女生没有学过英语,听不懂
他就没有必要说英文,说她能听懂的语言,说汉语就可以,说“我爱你” ---协议
IP地址:
网络中计算机唯一标识
但是呢,我们计算机只能识别二进制的数据,所以我们想IP地址在计算机中存储的时候应该也是由二进制的形式进行存储的
IP:192.168.7.42
换算成二进制:11000000.10101000.00000111.00101010
实际上存储的是:11000000101010000000011100101010,这样的存储形式,我们在学习过程中,难免会遇到配置网络地址的操作,这样的IP地址
从记忆和书写层面上来说都是很麻烦的
为了方便IP地址的表示,就把IP地址上的每一个字节上的数据转换成十进制,然后字节与字节之间用.分割标识
这样的表示法:点分十进制表示法
11111111
IP地址的组成:网络号段+主机号段
IP地址的分类:
A:定义一个号段定义为网络号段+后面三个号段都是为主机号段
可以有多台主机相连:256*256*255
B:前两个号段为网络号段+最后一个号段为主机号段 256*255
C:前三个号段都是为网络号段+最后一个号段为主机号段 255 局域网
D:224.0.0.1---239.255.255.254
E:240.0.0.1---247.255.255.254
特殊的IP地址:
1、localhost = 本机 = 127.0.0.1
127.0.0.1回环地址,可以用于测试本机的网络是否有问题,ping127.0.0.1
2、广播地址:
x.x.x.255
3、网络地址:
x.x.x.0
三个DOS命令:
ipconfig Windows:查看ip地址
Linux:
centOS6:ipconfig
centOS7:ip addr
ping:测试网络是否联通
ping + IP地址/host名
2、InetAddress
package com.shujia.lhw.day26.network;
import java.net.InetAddress;
/*
为了方便我们对IP地址的获取和操作,Java提供了一个类InetAddress供我们使用
public static InetAddress getByName(String host)
throws UnknownHostException确定主机名称的IP地址
*/
public class InetAddressDemo {
public static void main(String[] args) throws Exception{
InetAddress name = InetAddress.getByName("192.168.7.15");
System.out.println(name);
//public String getHostName()获取此IP地址的主机名
String hostName = name.getHostName();
System.out.println(hostName);
//public String getHostAddress()返回文本显示的IP地址字符串
String address = name.getHostAddress();
System.out.println(address);
}
}
3、ReceiveAndSend 1
package com.shujia.lhw.day26.network;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
UDP协议接收数据:
1、创建接收端的Socket对象
2、创建一个数据包(接收容器)
3、调用Socket对象的接收方法接收数据
4、解析数据包,得到数据并显示到控制台上
5、释放资源,关闭Socket
注意事项:
接收端程序在绑定同一个端口的时候不能同时运行多个
*/
public class ReceiveDemo1 {
public static void main(String[] args) throws Exception{
//1、创建接收端的Socket对象
//DatagramSocket(int port)
//构造数据报套接字并将其绑定到本地主机上的指定端口
DatagramSocket ds = new DatagramSocket(10086);
//2、创建一个数据包(接收容器)
//定义一个字节数组
byte[] bytes = new byte[1024];
int length = bytes.length;
//DatagramPacket(byte[] buf,int length)
//构造一个DatagramPacket用于接收长度的数据包 length
DatagramPacket datagramPacket = new DatagramPacket(bytes,length);
//3、调用Socket对象接收方法接收数据
ds.receive(datagramPacket);//程序阻塞,直到接收到数据
InetAddress address = datagramPacket.getAddress();
String ip = address.getHostAddress();
//4、解析数据包,得到数据并显示在控制台上
//public byte[] getData()返回数据缓冲区
byte[] data = datagramPacket.getData();
//public int getLength()返回要发送的数据的长度或接收到的数据的长度
int length1 = datagramPacket.getLength();
String s = new String(data,0,length1);
System.out.println(ip+"发送的数据为:"+s);
//释放资源,关闭Socket
ds.close();
}
}
package com.shujia.lhw.day26.network;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
UDP协议发送数据:
1、创建发送端的Socket对象
2、创建数据,并把数据打包
3、调用Socket对象的发送方法将数据发送数据
4、释放资源,关闭Socket
*/
public class SendDemo1 {
public static void main(String[] args) throws Exception{
//1、创建发送端的Socket对象DatagramSocket
//DatagramSocket()
//构造数据报套接字并将其绑定到本地主机上的任何可用端口
DatagramSocket ds = new DatagramSocket();
//2、创建数据,并把数据打包
byte[] bytes = "你好,大数据".getBytes();
//获取数组的长度
int length = bytes.length;
//要发送的IP地址
InetAddress address = InetAddress.getByName("192.168.7.15");
//设置端口号
int port = 10086;
//3、调用Socket对象的发送方法将数据发送出去
//DatagramPacket(byte[] buf,int length,InetAddress address,int port)
//构造用于发送长度的分组的数据报包 length指定主机上到指定的端口号
DatagramPacket packet = new DatagramPacket(bytes,length,address,port);
//从此套接字发送数据报包
//void send(DatagramPacket p)
ds.send(packet);
//4、释放资源,关闭Socket
ds.close();
}
}
4、ReceiveAndSend 2
package com.shujia.lhw.day26.network;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class ReceiveDemo2 {
public static void main(String[] args) throws Exception{
//1、创建接收端的Socket对象
DatagramSocket ds = new DatagramSocket(12345);
while (true){
//2、创建一个结束数据包
byte[] bytes = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(bytes,bytes.length);
//3、调用Socket对象的接受数据的方法接收数据
ds.receive(datagramPacket);
//4、解析数据
String ip = datagramPacket.getAddress().getHostAddress();
String hostName = datagramPacket.getAddress().getHostAddress();
byte[] data = datagramPacket.getData();
int length = datagramPacket.getLength();
String s = new String(data,0,length);
System.out.println(ip+":"+hostName+"发送的数据为:"+s);
}
}
}
package com.shujia.lhw.day26.network;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
/*
从键盘录入数据进行发送,如果输入的是886那么客户端就结束输入数据
*/
public class SendDemo2 {
public static void main(String[] args) throws Exception{
//1、创建发送端的Socket对象
DatagramSocket ds = new DatagramSocket();
//2、键盘录入数据
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line = null;
while((line=br.readLine())!=null){
if ("886".equals(line)){
break;
}
//如果输入的数据不是886,将数据打包发送出去
DatagramPacket packet = new DatagramPacket(line.getBytes(),line.getBytes().length, InetAddress.getByName
("192.168.7.15"),12345);
//调用Socket对象中发送数据包的方法
ds.send(packet);
}
//释放资源
ds.close();
}
}
5、ServerAndClient 1
package com.shujia.lhw.day26.network;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/*
TCP协议编写服务器代码:
1、创建服务器端Socket对象(ServerSocket)
2、调用accept()方法,监听客户端的连接,返回一个对应客户端连接的Socket对象
3、获取通道中的输入流对象,读取客户端发送的数据,并显示在控制台上
4、释放资源,关闭Socket服务
*/
public class ServerDemo1 {
public static void main(String[] args) throws Exception{
//1、创建服务器端Socket对象(ServerSocket)
//ServerSocket(int port)
//创建绑定到指定端口肚饿服务器套接字
ServerSocket ss = new ServerSocket(12345);
//调用accept()方法,监听客户端的连接,返回一个对应客户端连接的Socket对象
Socket s = ss.accept();
while(true){
//获取通道中的输入流对象
InputStream inputStream = s.getInputStream();
byte[] bytes = new byte[1024];
int length = inputStream.read(bytes);
String s1 = new String(bytes,0,length);
//获取客户端的IP
String ip = s.getInetAddress().getHostAddress();
String hostName = s.getInetAddress().getHostName();
System.out.println(ip+":"+hostName+"发送的数据为:"+s1);
}
}
}
package com.shujia.lhw.day26.network;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
/*
TCP协议客户端代码实现:
1、创建客户端的Socket对象
这一步如果成功创建对象,就说明连接已经建立成功
2、获取输出流对象,向服务器写数据
3、释放资源,关闭Socket服务
键盘录入数据
注意事项:
要先启动服务器端,再启动客户端,否则报连接被拒绝异常
*/
public class ClientDemo1 {
public static void main(String[] args) throws Exception{
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//创建发送端的Socket对象
//Socket(InetAddress,address,int port)
//创建流套接字并将其连接到指定的IP地址的指定端口号
// Socket s = new Socket(InetAddress.getByName("192.168.7.15"),12345);
//Socket(String host,int port)
//创建流套接字并将其连接到指定主机上的指定端口号
Socket s = new Socket("192.168.7.15",12345);
//获取输出流对象,向服务器写数据
OutputStream os = s.getOutputStream();
while(true){
String next = sc.next();
if("886".equals(next)){
break;
}
os.write(next.getBytes());
}
//释放资源,关闭Socket服务
s.close();
}
}
6、ServerAndClient 2
package com.shujia.lhw.day26.network;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo2 {
public static void main(String[] args) throws Exception{
//1、创建服务器端的Socket对象
ServerSocket ss = new ServerSocket(12345);
//2、监听客户端的连接
Socket s = ss.accept();
//3、获取通道中字节输入流对象,接收客户端发送的信息
InputStream is = s.getInputStream();
//4、获取通道中的字节输出流对象,给客户端一个反馈
OutputStream os = s.getOutputStream();
while(true){
byte[] bytes = new byte[1024];
int length = is.read(bytes);
String string = new String(bytes,0,length);
String ip = s.getInetAddress().getHostAddress();
String hostName = s.getInetAddress().getHostName();
System.out.println(ip+":"+hostName+"发送的数据为:"+string);
os.write("服务器已经接收到数据".getBytes());
}
}
}
package com.shujia.lhw.day26.network;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo2 {
public static void main(String[] args) throws Exception{
//1、创建客户端Socket对象
Socket s = new Socket("192.168.7.15", 12345);
//2、获取通道中字节输出流对象,往服务器发送信息
OutputStream os = s.getOutputStream();
//3、获取通道中字节输入流对象,接收服务器给的反馈
InputStream is = s.getInputStream();
while(true){
Scanner sc = new Scanner(System.in);
String next = sc.next();
os.write(next.getBytes());
byte[] bytes = new byte[1024];
int length = is.read(bytes);
String string = new String(bytes, 0, length);
System.out.println("服务器给出反馈:"+string);
}
}
}
7、ServerAndClient 3
package com.shujia.lhw.day26.network;
import cn.tx.demo.WhileDemo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
/*
用多线程改进服务器端代码,实现可以让多个客户端与之建立联系
*/
public class ServerDemo3 {
public static void main(String[] args) throws Exception{
System.out.println("================服务器启动=====================");
//创建服务器端自身的Socket对象
ServerSocket ss = new ServerSocket(12345);
//监听的时候对应一个客户端,返回一个对相应的Socket对象
//定义一个循环不断地接收客户端的连接请求
while(true){
//开始接受客户端与服务器端之间的连接
Socket socket = ss.accept();
new ServerReaderThread(socket).start();
}
}
}
//定义与客户端连接操作的线程类
class ServerReaderThread extends Thread{
private Socket socket;
ServerReaderThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
//获取与客户端通道中的字节输入流对象
try {
InputStream is = socket.getInputStream();
//将字节输入流对象包装成字符流
InputStreamReader isr = new InputStreamReader(is);
//使用字符缓冲输入流
BufferedReader br = new BufferedReader(isr);
//IP
String ip = socket.getInetAddress().getHostName();
String hostName = socket.getInetAddress().getHostName();
//按照行来读取
String line;
while((line=br.readLine())!=null){
//获取到当前时间
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date2 = sdf.format(date);
System.out.println(date2);
System.out.println(ip+":"+hostName+"发送来的数据:"+line);
}
} catch (IOException e) {
// e.printStackTrace();
}
System.out.println("客户端"+socket.getInetAddress().getHostName()+"下线了...");
}
}
package com.shujia.lhw.day26.network;
import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
/*
*/
public class ClientDemo3 {
public static void main(String[] args) throws Exception{
//创建键盘录入对象
Scanner sc = new Scanner(System.in);
//创建客户端Socket对象
Socket s = new Socket("192.168.7.15",12345);
System.out.println("请输入想要发送的数据:");
//获取通道中字节输出流对象
OutputStream os = s.getOutputStream();
OutputStreamWriter osw = new OutputStreamWriter(os);
BufferedWriter bw = new BufferedWriter(osw);
while (true){
String next = sc.next();
if("886".equals(next)){
s.shutdownOutput();
break;
}
bw.write(next);
bw.newLine();
bw.flush();
}
s.close();
}
}