java基础第三周

第三周笔记

day01

字符流与字节流

  • 字符流:----传输的是字符,只能传输字符
    • 	字符写出流   Writer
      
      write() write(字符数组) write(字符串)
      字符读入流 Reader read() read(数组)
      字符缓冲写出流 BufferedWrite newline() 跨平台换行
      字符缓冲读入流 BufferedReader readLine() 读一行
  • 字节流:—传输的是字节,可以传输任何类型的数据
  • 	字节输出流     OutputStream
    	字节输入流     InputStream
    	字节缓冲输出流     BufferedOutputStream
    	字节缓冲输入流     BufferedInputStream
    

装饰设计模式:

装饰设计模式:基于已经实现的功能,提供增强的功能.

装饰设计模式的由来就来自于对缓冲流的实现.

特点: 从缓冲流的角度讲解

  • 1.使流原来的继承体更加的简单
  • 2.提高了效率
  • 3.由于是在原有的基础上提高增强的功能,所以他还要属于原来的体系

步骤:

  • 1.让BTest 继承自Test
  • 2.在BTest内有一个Test类型的成员变量
  • 3.通过BTest内一个带参数的构造方法接收外部传入的一个Test类型的对象,交给内部的Test的属性
  • 4.在实现功能的时候,调用传入的Test类型的对象实现原有的功能,自己实现增强的功能.

适配器设计模式:

通常可以变相的理解成装饰设计模式

模拟字符缓冲读入流:

分析:

  • 1.要属于流的体系
  • 2.要有一个Reader类型的成员变量
  • 3.要有一个带参数的构造方法接收外部传入的流对象
  • 4.模拟readLine(),实现读一行的功能
  • 5.关闭流

LineNumberReader:

LineNumberReader:是BufferedReader的子类,不能读.但是可以提高效率,特有功能:设置行号,获取行号

设置行号,默认从0开始,从1开始打印

lineNumberReader.setLineNumber(10);//从11行开始打印

LineNumberReader lineNumberReader = new LineNumberReader(new FileReader("D:\\workspace/BigData1923N19\\src\\com\\qf\\test\\Demo1.java"));
		//设置行号,默认从0开始,从1开始打印
		lineNumberReader.setLineNumber(10);
		String data = null;
		while ((data = lineNumberReader.readLine()) != null) {
			System.out.print(lineNumberReader.getLineNumber());//获取行号
			System.out.print(data);
			System.out.println();
		}
		lineNumberReader.close();

字节流读取

	public static void main(String[] args) throws IOException {
		//写入数据
		write();
		//读1
		read1();
		//读2
		read2();
		//读3
		read3();
	}
	//将数据写入磁盘
	public static void write() throws IOException {
		//1.创建字节输出流并关联文件
		FileOutputStream fileOutputStream = new  FileOutputStream("test1.txt");
		//2.写--这里只能写字节
		fileOutputStream.write("bingbing".getBytes());
		//3.关闭资源
		fileOutputStream.close();
	}
	//读1 一次读一个字节
	public static void read1() throws IOException {
		//1.创建字节输入流并关联文件
		FileInputStream fileInputStream = new FileInputStream("test1.txt");
		//2.读
		int num = 0;
		while ((num = fileInputStream.read()) != -1) {
			System.out.print((char)num);
		}
		//3.关闭资源
		fileInputStream.close();
	}
	//读2   一次读多个字节
	public static void read2() throws IOException {
		//1.创建字节输入流并关联文件
		FileInputStream fileInputStream = new FileInputStream("test1.txt");
		//2.读
		int num = 0;
		byte[] bytes = new byte[5];
		while ((num = fileInputStream.read(bytes)) != -1) {
			System.out.print(new String(bytes,0,num));
		}
		//3.关闭资源
		fileInputStream.close();
	}
	//读3  一次全部读完
	public static void read3() throws IOException {
		//1.创建字节输入流并关联文件
		FileInputStream fileInputStream = new FileInputStream("test1.txt");
		//获取文件的字节个数
		//注意:这种方式适合文件的字节数比较小的时候,大概是几kb之内.
		int num1 = fileInputStream.available();
		//2.读
		byte[] bytes = new byte[num1];
		fileInputStream.read(bytes);
		System.out.println(new String(bytes));
		//3.关闭资源
		fileInputStream.close();
	}
}

标准输入流和标准输出流(默认字节流)

  • 标准输入流:–System.in:“标准”输入流。此流已打开并准备提供输入数据。通常,此流对应于键盘输入或者由主机环境或用户指定的另一个输入源。

    输入源:可以发送数据的设备 输出源:可以接收数据的设备
    1.当前的流已经打开并关联了输入源–键盘
    2.如果不想让键盘充当输入源,可以通过setIn进行更换
    3.是一个字节流

  • 标准输出流:–System.out

阻塞式方法

        InputStream inputStream = System.in;

		//int num = inputStream.read();//把标准输入流的read方法称为阻塞式方法

转换流

  • 转换流:实现的是从字节流到字符流,本身是字符流
  • 模拟的场景:使用字符缓冲流的readline和newline方法实现字节流的功能
  • InputStreamReader:输入转换流
  • OutputStreamWriter:输出转换流
以reader 和writer结尾的是字符流
以stream结尾的是字节流
public static void main(String[] args) throws IOException {
		//1将标准字节输入流转成字符缓冲读入流
		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
		//2.将标准字节输出流转成字符缓冲写出流
		BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));
		//3.读写
		String data = null;
		while ((data = bufferedReader.readLine()) != null) {
			bufferedWriter.write(data);
			bufferedWriter.newLine();
			bufferedWriter.flush();
			//当输入的内容是over时,结束
			if (data.equals("over")) {
				break;
			}
		}
		bufferedReader.close();
		bufferedWriter.close();
	}
更换数据源

​ //注意:这里是临时更换,只能在当前程序中使用更换后的输入源输出源,如果在其他的程序中会自动变回原来的输入源输出源
//从键盘接收数据更替成从文件接收数据
System.setIn(new FileInputStream(“D:\workspace\BigData1923N20\src\com\qf\test\Demo1.java”));
//从输出到控制台更替成输出到文件
System.setOut(new PrintStream(“D:\workspace\BigData1923N20\Democopy.java”));

	BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
	BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(System.out));

打印流

字节打印流:PrintStream:除了拥有输出流的特点之外,还有打印的功能.

字符打印流:PrintWriter

字符比字节多一种字符流

字节打印流支持的设备:

  • 1.File类型的文件
  • 2.字符串类型的文件
  • 3.字节输出流

Properties

properties: 实际上就是Map集合,存储的是属性,属性以键值对的方式存储.这里的键和值都必须是字符串.所以不需要考虑泛型

为什么要在这里讲Properties?

因为他的使用与流紧密相关

优点:
  • 1.以键值对的形式存储数据
  • 2.内部针对属性的存储封装了大量的专有方法:load(读入),store(写出),list
1.Properties的基础
public static void fun1() {
		//创建对象
		Properties properties = new Properties();
		properties.setProperty("a", "java");
		properties.setProperty("b", "html");
		System.out.println(properties);
		//根据key取值
		System.out.println(properties.getProperty("a"));
		//key是唯一的
		Object object = properties.setProperty("a", "BigData");
		System.out.println(object);
		//当前的key在Properties中不存在时,会打印python
		System.out.println(properties.getProperty("c", "python"));
		
	}
2.利用Properties获取系统属性
public static void fun2() {
			//获取系统属性
			Properties properties = System.getProperties();
			//遍历
			Set<String> set = properties.stringPropertyNames();
		Iterator<String> iterator =set.iterator();
		while(iterator.hasNext()){
			String string = (String)iterator.next();
				System.out.println("key:"+string+"  value "+properties.getProperty(string));
			}
			
		//增强for循环
			for(String key : set){
		    System.out.println("key:"+key+"  value "+properties.getProperty(key));

			}
			
			//对系统的某个属性进行修改
			properties.setProperty("sun.jnu.encoding", "UTF8");
			System.out.println(properties.getProperty("sun.jnu.encoding"));
			
			//重新获取一遍值
			//原理:会先到内存中找属性集合的对象,如果有,直接使用.如果没有,会重新初始化一个新的对象,并获取属性集合.
			Properties properties1 = System.getProperties();
			System.out.println(properties1.getProperty("sun.jnu.encoding"));
		
		   properties.list(System.out);
		
		}
3.Properties在实际中的使用
  public static void fun3() throws FileNotFoundException, IOException{
			//创建properties对象
        	 Properties properties = new Properties();
        	 //利用load方法将内容从磁盘读到内存
        	 //注意:使用的文件内容的格式应用时key=value
        	 properties.load(new FileReader("test01.txt"));
        	 properties.list(System.out);
        	 //更改内容
        	 properties.setProperty("a", "woaini");
        	 //写入磁盘,第二个参数是提醒信息
        	 properties.store(new FileWriter("test01.txt"), "hello  wuxi");
        	 }

序列化(demo13)

  1. 序列化流: 将短期存储的数据实现长期存储,这个过程对应的流就是序列化流

  2. 序列化: 将数据从内存放入磁盘,可以实现数据的长久保存–数据持久化的手段

  3. 反序列化: 将数据从磁盘放回内存

  4. 数据的存储分为两类 短期存储:存放在内存中,随着程序的关闭而释放—对象,集合,变量,数组 长期存储:存储在磁盘中,即使程序关闭了,数据仍然存在------文件

  5. 进行序列化的步骤:----通过对象的序列化讲解 1.创建一个类 2.使用对应的流将对象存入磁盘中----序列化----ObjectOutputStream 3.使用对应的流将对象从磁盘中取出放回内存–反序列化------ObjectInputStream 4.关闭流

  6. 注意点:序列化流在工作时也要关联对应的基本的输入流和输出流

  7. 进行序列化的步骤:–通过对象的序列化讲解

    • 1.创建一个类

    • 2.使用对应的流将对象存入磁盘中----序列化----ObjectOutputStream

    • 3.使用对应的流将对象从磁盘中取出放回内存–反序列化------ObjectInputStream

    • 4.关闭流

      public class 序列化练习 {
      
      	public static void main(String[] args) throws Exception{
      		
      	String string =  "张三,10,170;李四,12,173;王五,15,176";
      	
      	String[] str = string.split("[,;]");
      	
      	
      	List<Persons> list = new ArrayList<Persons>();
      	
      	for (int i = 0; i < str.length; i+=3) {
      	
      		 Persons persons = new Persons(str[i],Integer.parseInt(str[1+i]),Double.parseDouble(str[2+i]));
      		
      		
      		list.add(persons);
      	}
      	System.out.println(list);
      	
      	//序列化
      	ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("test01.txt"));
      	
      	objectOutputStream.writeObject(list);
      	
      	objectOutputStream.close();
      	
      	
      	//逆序列化
      	ObjectInputStream objectInputStream = new  ObjectInputStream(new FileInputStream("test01.txt"));
      	
      	Object object = objectInputStream.readObject();
      	List<Persons> list2 = (List<Persons>) object;
      	
      	System.out.println(list2);
      	objectInputStream.close();
      	}
      
      	
      }
      class Persons implements Serializable{
      	String name;
      	int age;
      	double height;
      	@Override
      	public String toString() {
      		return "Persons [name=" + name + ", age=" + age + ", height=" + height + "]";
      	}
      	public Persons() {
      		super();
      		// TODO Auto-generated constructor stub
      	}
      	public Persons(String name, int age, double height) {
      		super();
      		this.name = name;
      		this.age = age;
      		this.height = height;
      	}
      	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 double getHeight() {
      		return height;
      	}
      	public void setHeight(double height) {
      		this.height = height;
      	}
      }
      
      

File类(demo14)

public static void main(String[] args) throws IOException {
		/*
		 * 文件:File类,用来操作文件和路径(目录)
		 * 
		 * 创建文件
		 * 创建路径
		 * 创建多路径
		 * 
		 * 判断是否是文件
		 * 判断是否是路径
		 * 判断是否隐藏
		 * 获取最后修改文件的时间
		 * 
		 * 获取根目录(路径)
		 * 获取指定目录下的文件或文件夹
		 */
		//创建File类的对象
		//第一种方式:直接指定文件的绝对路径
		File file1 = new File("D:\\workspace\\BigData1923N21\\src\\com\\qf\\test\\Demo1.java");
		//第二种:通过父路径和子路径的字符串形式
		File file2 = new File("D:\\workspace\\BigData1923N21","src\\com\\qf\\test\\Demo1.java");
		//第三种:先得到父路径的对象形式,再跟子路径拼接
		File file3 = new File("D:\\workspace\\BigData1923N21");
		File file4 = new File(file3,"src\\com\\qf\\test\\Demo1.java");
//		 * 创建文件,在创建时,如果当前的文件已经存在了,不会覆盖
		File file5 = new File("D:\\workspace\\BigData1923N21\\test1.txt");
		file5.createNewFile();
//		 * 创建单层路径,只能创建单层路径,只能创建目录
		File file6 = new File("D:\\workspace\\BigData1923N21\\a\\test2.txt");
		file6.mkdir();
//		 * 创建多路径,也可创建单层目录,只能创建目录
		file6.mkdirs();
		
//		 * 判断是否是文件
		System.out.println(file6.isFile());//false
//		 * 判断是否是路径
		System.out.println(file6.isDirectory());//true
//		 * 判断是否隐藏
		System.out.println(file6.isHidden());//false
//		 * 获取最后修改文件的时间
		long lastTime = file5.lastModified();
		System.out.println(lastTime);
		
		SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String value = simpleDateFormat.format(new Date(lastTime));
		System.out.println(value);
	}

demo16,demo17留作业

功能:作业:要求遍历当前目录下的所有文件----利用递归实现

实例:求1-10之间的偶数的积与奇数的积的差—利用递归

编码

  1. 编码:将字符串转化成byte序列的过程
  2. 解码:是将byte序列转成字符串的过程
  3. 编码错误:乱码:在执行读与写的时候,由于使用的字符集不同,造成了编码的错误.

中文乱码出现的情况研究:

  • 但是如果是编码出错了,无法解决.如果是解码出错了,可以利用再编码再解码
    • 编码 解码 结果
      BK utf8 不可以(GBK2个字节,utf83个字节)
      BK ISO8859-1 可以
      tf8 GBK 有时可以
      tf8 ISO8859-1 可以
      SO8859-1 GBK 不可以(编码就出错了)
      SO8859-1 utf8 不可以(编码就出错了)

day01重点:装饰器模式(demo01),properties(demo12),序列化(demo13),file类(demo14)

day02

NIO

(jdk1.4开始)

Java NIO 由以下几个核心部分组成:
  • Channels:通道 Buffer:缓冲区 Selectors:选择器

  • Channels和Buffer是新IO中的两个核心对象,Channel是对传统的输入/输出系统的模拟,在新IO系统中所有的数据都需要通过通道传输。

  • Channels与传统的InputStream,OutputStrem最大的区别在于它提供了一个map()方法,通过该map()方法可以直接将"一块数据"映射到

  • 内存中,如果说传统的输入/输出系统是面向流处理,则新IO则是面向块的处理

  • Buffer可以被理解为一个容器(缓冲区,数组),发送到Channel中的所有对象都必须首先放到Buffer中,而从Channel中读取的数据也必须

  • 放到Buffer中,也就是说数据可以从Channel读取到Buffer中,也可以从Buffer写到Channel中

    使用Buffe

  • Buffer就像一个数组,它可以保存多个类型相同的数据,Buffer是一个抽象类其最常用的类是ByteBuffer,它可以在底层字节数组上进行

  • get/set操作,除了ByteBuffer之外,对应于其他基本数据类型(boolean除外)都有相应的Buffer类

NIO与IO的区别:

1.IO面向流,NIO面向缓冲区

  • Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。

  • 此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。

  • Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。

  • 这就增加了处理过程中的灵活性

    2.IO是阻塞式的,NIO有非阻塞式的

  • Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,

  • 或数据完全写入。该线程在此期间不能再干任何事情了。Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,

  • 但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,

  • 所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。

    3.IO没有选择器,NIO有选择器

  • Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,

  • 然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。

  • 这种选择机制,使得一个单独的线程很容易来管理多个通道

      使用Buffer读写数据一般遵循以下四个步骤:
     1. 写入数据到Buffer
     2. 调flip()方法
     3. 从Buffer中读取数据
     4. 调用clear()方法或者compact()方法
        当向buffer写入数据时,buffer会记录下写了多少数据。一旦要读取数据,需要通过flip()方法将Buffer从写模式切换到
        读模式。在读模式下,可以读取之前写入到buffer的所有数据。
        一旦读完了所有的数据,就需要清空缓冲区,让它可以再次被写入。有两种方式能清空缓冲区:调用clear()或compact()方法。
        clear()方法会清空整个缓冲区。compact()方法只会清除已经读过的数据。任何未读的数据都被移到缓冲区的起始处,
        新写入的数据将放到缓冲区未读数据的后面。
    

NIO.2

  • Java7对原有NIO进行了重大改进,改进主要包括如下两个方面的内容
  • 1.提供了全面的文件IO和文件系统访问支持
  • 2.基于异步Channel的IO
  • Path、Paths和Files
  • 之前学习中学习过File类来访问文件系统,但是File类的功能比较有限,NIO.2为了弥补这种不足,
  • 引入了一个Path接口还提供了Files和Paths两个工具类,其中Files分装了包含大量静态方法来操作文件,
  • Paths则包含了返回Path的静态工厂方法

网络通信

  1. 三大要素:IP , 端口号 ,协议
  2. IP:可以在网络中唯一的标记一台主机 -----------java中将IP面向对象了–InetAddress
  3. 端口:用来区分一台主机上的多个服务器(不可以重复) 取值范围:(0,65535) 注意点:在通信时两边的端口号要一致
  4. 网络协议:相当于指定的一个统一的标准
  5. URL:统一资源定位器
  6. URI:统一资源定位符
  7. URL的功能:可以通过它的方法直接获取网址的各个部分,还可以访问网络的资源 System.out.println(url.getProtocol());//协议
    System.out.println(url.getPath());//资源路径System.out.println(url.getHost());//主机名/域名/IP地址
    System.out.println(url.getQuery());//查询条件
    System.out.println(url.getPort());//端口
    System.out.println(url.getDefaultPort());//默认端口 443
    //System.out.println(url.getContent());//查询的内容
  8. URLConnection代表客户端与服务器端的通信通道,这个类的实例可以用于读取或者写入url引入的资源
public class Demo3 {
	public static void main(String[] args) throws IOException {
		URL url = new URL("https://www.bingbing.com:333/a/b?name=bing&age=18");
		System.out.println(url.getProtocol());//协议
		System.out.println(url.getPath());//资源路径
		System.out.println(url.getHost());//主机名/域名/IP地址
		System.out.println(url.getQuery());//查询条件
		System.out.println(url.getPort());//端口
		System.out.println(url.getDefaultPort());//默认端口    443
		//System.out.println(url.getContent());//查询的内容
		
		URL url2 = new URL("https://www.baidu.com");
		//System.out.println(url2.getContent());
		//URLConnection代表客户端与服务器端的通信通道,这个类的实例可以用于读取或者写入url引入的资源
		URLConnection connection = url2.openConnection();
		
		//获取内部的字节输入流
		InputStream inputStream = connection.getInputStream();
		//进行读写
		byte[] arr = new byte[1024];
	     inputStream.read(arr);
	     System.out.println(new String(arr,"utf8"));
	}
}

UDP通信

模拟UDP通信
客户端

  • 1.创建UDP通信的对象-socket对象:对应的类是DatagramSocket.(用于UDP数据的发送与接收)

  • 2.数据的准备-封装包:DatagramPacket(数据包,包括相关的属性,数据)

  • 3.发送数据,通过send方法

  • 4.关闭socket对象

    //客户端
    public class Demo6 {
    	public static void main(String[] args) throws IOException {
    		 //* 1.创建UDP通信的对象-socket对象:对应的类是DatagramSocket.(用于UDP数据的发送与接收)
    		DatagramSocket socket = new DatagramSocket();
    //		 * 2.数据的准备-封装包:DatagramPacket(数据包,包括相关的属性,数据)
    		 /* 打包
    		 * 参数一:要传输的数据
    		 * 参数二:数据的长度
    		 * 参数三:服务器所在主机的地址
    		 * 参数四:服务器的端口
    		 */
    		BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
    		String data = null;
    		while ((data = bufferedReader.readLine()) != null) {
    			DatagramPacket packet = new DatagramPacket(data.getBytes(), data.length(), InetAddress.getLocalHost(), 20000);
    			 //* 3.发送数据,通过send方法
    			socket.send(packet);
    			
    			//当输入over的时候结束
    			if (data.equals("over")) {
    				break;
    			}
    		}
    		
    		 //* 4.关闭socket对象
    		socket.close();
    	}
    }
    
    

服务器端:接收数据

1.创建socket对象,并绑定端口号—DatagramSocket
2.创建包对象,创建空数组,准备接收传来的数据 3.接收数据 4.关闭相关的对象

public class Demo7 {
	public static void main(String[] args) throws IOException {
		System.out.println("启动服务器成功,可以随时接收数据");
		 // * 1.创建socket对象,并绑定端口号---DatagramSocket
		DatagramSocket socket  = new DatagramSocket(20000);
		//不断的接收数据
		while (true) {
			 //* 2.创建包对象,创建空数组,准备接收传来的数据
			byte[] buf = new byte[1024];
			DatagramPacket packet = new DatagramPacket(buf, buf.length);
			 //* 3.接收数据:当服务器运行起来,让他一直处于监听状态的方法
			socket.receive(packet);
			//显示所有数据
			byte[] bytes = packet.getData();
			String data = new String(bytes);
			System.out.println(new String(bytes));
			//当输入over的时候结束
			if (data.trim().equals("over")) {
				break;
			}
		}

		 //* 4.关闭相关的对象
		//socket.close();
	}
}

TCP通信

  • TCP:

  • 在客户端与服务器端通信的时候,对于客户端既要进行输入又要进行输出,所以在Socket对象的内部就内置了输入流和输出流,

  • 当进行数据传输的时候,将数据放入socket对象的内部,将socket对象传到服务器端,相当于在客户端与服务器端建立了一个通道,

  • 两端使用同一个socket对象.

//TCP的客户端
public class Demo8 {
	public static void main(String[] args) throws IOException {
		
		//1.创建Socket对象并绑定端口,管理服务器主机
		Socket socket = new Socket(InetAddress.getLocalHost(), 30000);
		//2.准备数据
		String data = "BigData1924,你好";
		//3.调用Socket内部的输出流向网络写数据
		OutputStream outputStream = socket.getOutputStream();
		outputStream.write(data.getBytes());
		
		//3.使用socket的输入流将服务器回传的信息打印
		InputStream inputStream = socket.getInputStream();
		//将内容打印到控制台
		byte[] arr = new byte[100];
		int num = inputStream.read(arr);
		String data1 = new String(arr,0,num);
		System.out.println(data1);
		
		socket.close();
	}
}

//服务器端
public class Demo9 {
	public static void main(String[] args) throws IOException {
		//1.创建ServerSocket对象并设置端口
		ServerSocket serverSocket = new ServerSocket(30000);
		//2.接收从客户端传来的socket对象
		Socket socket = serverSocket.accept();
		//3.使用socket的输入流卸货
		InputStream inputStream = socket.getInputStream();
		//将内容打印到控制台
		byte[] arr = new byte[100];
		int num = inputStream.read(arr);
		String data = new String(arr,0,num);
		System.out.println(data);
		
		//给客户端回发一个信息,告知接收成功
		//获取socket的输出流
		OutputStream outputStream = socket.getOutputStream();
		outputStream.write("你好,BigData1924".getBytes());
		
		//4.关闭资源
		serverSocket.close();
	}
}

day03

反射

反射:动态获取类的字节码文件,并对其成员进行抽象

整体的含义:就是想通过字节码文件直接创建对象

过程:1.获取字节码文件对象,

  • 先讲解获取字节码文件对象
    //1.通过Object提供的getClass()方法
  • 首先必须要有一个对象 XXX
    //2.通过每种数据类型都有的一个class属性
  • 在使用的位置必须当前的类是可见的,因为这里要显示的使用这个类名,对类的依赖性太强,使用不方便 XXX
    //3.Class类提供的一个静态方法forName(字符串) 字符串:包名+类名
  • 我们只需要提供一个当前类的字符串形式即可
public class Demo1 {
	public static void main(String[] args) throws ClassNotFoundException {
		//1.通过Object提供的getClass()方法
		 fun1();
		//2.通过每种数据类型都有的一个class属性
		 fun2();
		//3.Class类提供的一个静态方法forName(字符串)   字符串:包名+类名
		 fun3();
	}
	public static void fun1() {
		Person person = new Person();
		Class<?> class1 = person.getClass();
		Class<?> class2 = person.getClass();
		System.out.println(class1 == class2);//true  
	}
	public static void fun2() {
		Class<?> class1 = Person.class;
		System.out.println(class1.getName());
	}
	public static void fun3() throws ClassNotFoundException {
		//注意:要保证至少字符串对应的类是存在的
		Class<?> class1 = Class.forName("com.qf.test.Person");
	}
}

​ 2.通过字节码文件对象获取对应的实列对象

public class Demo2 {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		//普通方式
		//Person person = new Person();
		
		//通过反射创建普通对象
		Class<?> class1 = Class.forName("com.qf.test.Person");
		//方法一:通过无参的构造方法创建实例对象
		fun1(class1);
		//方法二:通过有参的构造方法创建实例对象
		fun2(class1);
	}
	//方法一:通过无参的构造方法创建实例对象
	public static void fun1(Class<?> cls) throws InstantiationException, IllegalAccessException {
		//创建实例对象
		//这里相当于在newInstance方法的内部调用了无参的构造方法
		Object object = cls.newInstance();
		Person person = (Person)object;
		person.setName("bingbing");
		System.out.println(person.getName());
	}
	//方法二:通过有参的构造方法创建实例对象
	public static void fun2(Class<?> cls) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		//先得到有参的构造方法
		//这里要写参数的字节码文件对象形式        所有的类型都有字节码文件对象
		//相当于  public Person(String name, int age)
		Constructor constructor = cls.getConstructor(String.class,int.class);
		Object object = constructor.newInstance("bingbing",18);
		System.out.println(object);
	}
}

​ 3.给属性赋值(通过从属性中提取出来的类–Fileld)

public class Demo3 {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException, SecurityException {
		Person person = new Person();
		//person.name = "bingbing";
		
		//使用反射实现
		//1.获取字节码文件对象
		Class<?> class1 = Class.forName("com.qf.test.Person");
		
		//2.获取实例对象
		Object object = class1.newInstance();
		
		//3.调用属性
		//注意:如果想使用getField,name属性必须是public的
		//Field field1 = class1.getField("name");
		//如果name是私有的,我们可以这样做   ,忽略权限
		Field field1 = class1.getDeclaredField("name");
		field1.setAccessible(true);
		//赋值
		//第一个参数:关联的具体对象
		//第二个参数:赋的值
		field1.set(object, "bing");
		
		System.out.println(field1.get(object));
	}
}

​ 4.调用方法(通过从方法中提取出来的类)

public class Demo4 {
	@Test
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		//使用反射实现
		//1.获取字节码文件对象
		Class<?> class1 = Class.forName("com.qf.test.Person");
		
		//调用非静态无参
		fun1(class1);
		//调用非静态有参
		fun2(class1);
		//调用静态有参
		fun3(class1);
	}
	//调用非静态无参
	public static void fun1(Class<?> cla) throws InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException {
		//2.获取实例对象
		Object object = cla.newInstance();
		//3.通过反射得到方法
		Method method = cla.getMethod("show");
		//4.调用方法,通过调用invoke方法实现
		method.invoke(object);
	}
	//调用非静态有参
	public static void fun2(Class<?> cla) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		//2.先得到有参的构造方法
		Constructor<?> constructor = cla.getConstructor(String.class,int.class);
		Object object = constructor.newInstance("bingibn",10);
		
		//3.通过反射得到方法
		Method method = cla.getMethod("callPhone",String.class);
		//4.调用方法,通过调用invoke方法实现
		method.invoke(object,"110");
	}
	//调用静态有参
	public static void fun3(Class<?> cla) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
		//3.通过反射得到方法
		Method method = cla.getMethod("run",int.class);
		//4.调用方法,通过调用invoke方法实现
		method.invoke(null,11);
	}
}

静态代理

作用:可以实现代理
作用:根据OCP(对扩展开放,对修改关闭)的原则,在不改变原来类的基础上,给这个类增加额外的功能
缺点:代理对象要保证跟目标对象实现同样的接口,在维护的时候两个对象都要维护,
而且代理对象实现的接口是死的,这时如果要给想实现不同功能的多个目标对象添加代理对象的话,要添加很多个类

主要是代理类的编写(这里写的是找房子住的代理)

public class Agent implements TestInter{//TestInter中写的是找房子方法
	//先给他个人
	TestInter person;
	public Agent(TestInter person) {
		super();
		this.person = person;
	}
	public void findHouse() {
		System.out.println("扣一个月的房租作为中介费");
		person.findHouse();
		System.out.println("哈哈大笑");
	}
}

动态代理

动态生成代理对象的方法–通过JDK内置的java.lang.reflect.Proxy动态代理类完成代理对象的创建
参数一:这里代表类加载器,代理类的类加载器要与目标类的类加载器一致,类加载器用来装载内存中的字节码文件
参数二:代理类与目标类实现的接口必须有相同的,即指定给代理类的接口,目标类必须实现了
参数三:代理类的构造方法生成的对象–注意:指定给构造方法的参数要使用Object

主要是代理类的编写

public class Test {
	//模拟功能:bingbing和chenchen找房住
	public static void main(String[] args) {
		//静态代理
//		Bingbing bingbing = new Bingbing();
//		//bingbing.findHouse();
//		Agent agent = new Agent(bingbing);
//		agent.findHouse();
		
		//动态代理
		TestInter testInter = new Bingbing();
		//调用动态代理的方法实现功能
		/**
		 *动态生成代理对象的方法--通过JDK内置的java.lang.reflect.Proxy动态代理类完成代理对象的创建
		 *参数一:这里代表类加载器,代理类的类加载器要与目标类的类加载器一致,类加载器用来装载内存中的字节码文件
		 *参数二:代理类与目标类实现的接口必须有相同的,即指定给代理类的接口,目标类必须实现了
		 *参数三:代理类的构造方法生成的对象--注意:指定给构造方法的参数要使用Object
		 * 
		 */
//		TestInter object = (TestInter)Proxy.newProxyInstance(testInter.getClass().getClassLoader(), new Class[] {TestInter.class}, new Agent(testInter));
		//代理对象调动方法的时候,invoke方法会自动被调用
//		object.findHouse();
//		
//		TestEat testEat = new Langlang();
//		TestEat object1 = (TestEat)Proxy.newProxyInstance(testEat.getClass().getClassLoader(), new Class[] {TestInter.class,TestEat.class}, new Agent(testEat));
//		object1.eat();
		
		//进一步优化----直接使用InvocationHandler创建匿名内部类干活儿,不再需要Agent类
		TestInter object2 = (TestInter)Proxy.newProxyInstance(testInter.getClass().getClassLoader(), new Class[] {TestInter.class}, 
			new InvocationHandler() {
				public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
					System.out.println("扣一个月的房租作为中介费");
					Object object = method.invoke(testInter, args);
					System.out.println("哈哈大笑");
					return object;
				}
		   }
		);
		object2.findHouse();
		
		TestEat testEat = new Langlang();
		TestEat object3 = (TestEat)Proxy.newProxyInstance(testEat.getClass().getClassLoader(), new Class[] {TestInter.class,TestEat.class}, new InvocationHandler() {
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				System.out.println("先洗后");
				Object object = method.invoke(testEat, args);
				System.out.println("哈哈大笑");
				return object;
			}
	   });
		object3.eat();
		
		//使用工厂方法
		TestInter testInter3 = TestFactory.getAgentFactory(testInter);
		testInter3.findHouse();
	}
}


//创建一个工厂类---用于创建代理对象
public class TestFactory {
	//工厂方法
	public static TestInter getAgentFactory( final TestInter test) {
  //final TestInter test = new Bingbing();
		
		TestInter agent = (TestInter)Proxy.newProxyInstance(test.getClass().getClassLoader(), new Class[]{TestInter.class}, new InvocationHandler() {
			
			@Override
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				// TODO Auto-generated method stub
				System.out.println("扣一半房租做中介费");
				// TODO Auto-generated method stub
				//通过反射的方法调用具体对象的方法
				Object object = method.invoke(test, args);
				
				System.out.println("哈哈大笑");
				
				return object;
			}
		});
		
		return agent;
	}

}

线程池(抽时间看)

ThreadPool(线程池)+CountDownLatch(程序计数器)

顾名思义,CountDownLatch为线程计数器,他的执行过程如下:
首先,在主线程中调用await()方法,主线程阻塞,
然后,将程序计数器作为参数传递给线程对象,
最后,每个线程执行完任务后,调用countDown()方法表示完成任务。
countDown()被执行多次后,主线程的await()会失效。

day04

mysql数据库

Sql****的分类

​ DDL(*)

(Data Definition Language):数据定义语言,用来定义数据库对象:库、表、列等;

DML(**)

(Data Manipulation Language):数据操作语言,用来定义数据库记录(数据);

DCL

(Data Control Language):数据控制语言,用来定义访问权限和安全级别;

DQL(*****)

(Data Query Language):数据查询语言,用来查询记录(数据)。

[外链图片转存失败(img-QYjdfhgr-1567949580326)(E:\web开发项目文件\Typora\1565408914561.png)]

day05

DDL:操作数据库、表、列等

一:对数据库的操作

创建

Createdatabase mydb1;

Create database mydb2 character setgbk;

Create database mydb3 character setgbk COLLATE gbk_chinese_ci;

查询

查看当前数据库服务器中的所有数据库

Show databases;

查看前面创建的mydb2数据库的定义信息

Show create database mydb2;

删除前面创建的mydb3数据库

Drop database mydb3;

修改

查看服务器中的数据库,并把mydb2的字符集修改为utf8;

alter database mydb2 character set utf8;

删除

Drop database mydb3;

其他:

查看当前使用的数据库

Select database();

切换数据库

Use mydb2;

二:操作数据表

当前数据库中的所有表 SHOWTABLES;

查看表的字段信息 DESCemployee;

在上面员工表的基本上增加一个image列。 ALTERTABLE employee ADD image blob;

修改job列,使其长度为60。 ALTERTABLE employee MODIFY job varchar(60);

删除image列,一次只能删一列。 ALTERTABLE employee DROP image;

表名改为user。 RENAMETABLE employee TO user;

查看表格的创建细节 SHOWCREATE TABLE user;

修改表的字符集为gbk ALTERTABLE user CHARACTER SET gbk;

列名name修改为username ALTERTABLE user CHANGE name username varchar(100);

备份表结构和表数据 create tabletname2 as select * from tname1;

备份表结构 create tabletname2 like tname1;

删除表 DROP TABLE user ;

DML操作:据操作语言,用来定义数据库记录(数据)

一:插入:

练习:

create table emp(

id int,

name varchar(100),

gender varchar(10),

birthday date,

salary float(10,2),

entry_date date,

resume text

);

INSERTINTO emp(id,name,gender,birthday,salary,entry_date,resume)

VALUES(1,‘zhangsan’,‘female’,‘1990-5-10’,10000,‘2015-5-5-’,‘goodgirl’);

INSERT INTOemp(id,name,gender,birthday,salary,entry_date,resume)

VALUES(2,‘lisi’,‘male’,‘1995-5-10’,10000,‘2015-5-5’,‘goodboy’);

INSERT INTOemp(id,name,gender,birthday,salary,entry_date,resume)

VALUES(3,‘你’,‘male’,‘1995-5-10’,10000,‘2015-5-5’,‘good boy’);

查看数据库编码的具体信息

Showvariables like ‘character%’;

二:修改:

语法:UPDATE 表名 SET 列名1=列值1,列名2=列值2 。。。 WHERE 列名=值

三:删除

语法: DELETE FROM 表名【WHERE 列名=值】

delete删除表中的数据,表结构还在,删除后的数据还可以找回

truncate 删除是把表直接DROP掉,然后再创建一个同样的新表。Truncate

删除的数据不能找回。执行速度比 delete 快。

DQL数据查询语言(重要)

查询返回的结果集是一张虚拟表

重要的sql语句:
一:分组查询

当需要分组查询时需要使用GROUPBY子句,例如查询每个部门的工资和,这说明要使用部门来分组。

//注:凡和聚合函数(组函数)同时出现的列名,则一定要写在groupby 之后

聚合函数(组函数也叫统计函数):

聚合函数是用来做纵向运算的函数:

COUNT():统计指定列不为NULL的记录行数;

MAX():计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;

MIN():计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;

SUM():计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;

AVG():计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;

分组查询 : 查询每个部门的部门编号和每个部门的工资和:

SELECT deptno, SUM(sal)

FROM emp

GROUP BY deptno;

HAVING子句 : 查询工资总和大于9000的部门编号以及工资和:

SELECT deptno, SUM(sal)

FROM emp

GROUP BY deptno

HAVING SUM(sal) > 9000;

having与where的区别

1.having是在分组后对数据进行过滤

​ where是在分组前对数据进行过滤

  1. having后面可以使用分组函数(统计函数)

​ where后面不可以使用分组函数。

WHERE是对分组前记录的条件,如果某行记录没有满足WHERE子句的条件,那么这行记录不会参加分组;而HAVING是对分组后数据的约束。

LIMIT

LIMIT用来限定查询结果的起始行,以及总行数。

select * from emp limit 3,10;

3代表起始行为3; 10代表行数 (从第三行开始往下10行)

重要点:

1.使用统计查询时(存在GROUP BY子句),SELECT子句之中只允许出现统计函数与分组字段,其它的任何字段都不允许出现。

2.统计函数单独使用时(没有GROUP BY子句)只能够出现统计函数,不能够出现其它字段

3.此错误的意思就是where子句中不能使用组函数,因为where子句是在group by子句之前先执行的,所以在sql中要想给分组后的内容进行筛选则要依赖与having子句。

truncate 删除是把表直接DROP掉,然后再创建一个同样的新表。Truncate

删除的数据不能找回。执行速度比 delete 快。

DQL数据查询语言(重要)

查询返回的结果集是一张虚拟表

重要的sql语句:
一:分组查询

当需要分组查询时需要使用GROUPBY子句,例如查询每个部门的工资和,这说明要使用部门来分组。

//注:凡和聚合函数(组函数)同时出现的列名,则一定要写在groupby 之后

聚合函数(组函数也叫统计函数):

聚合函数是用来做纵向运算的函数:

COUNT():统计指定列不为NULL的记录行数;

MAX():计算指定列的最大值,如果指定列是字符串类型,那么使用字符串排序运算;

MIN():计算指定列的最小值,如果指定列是字符串类型,那么使用字符串排序运算;

SUM():计算指定列的数值和,如果指定列类型不是数值类型,那么计算结果为0;

AVG():计算指定列的平均值,如果指定列类型不是数值类型,那么计算结果为0;

分组查询 : 查询每个部门的部门编号和每个部门的工资和:

SELECT deptno, SUM(sal)

FROM emp

GROUP BY deptno;

HAVING子句 : 查询工资总和大于9000的部门编号以及工资和:

SELECT deptno, SUM(sal)

FROM emp

GROUP BY deptno

HAVING SUM(sal) > 9000;

having与where的区别

1.having是在分组后对数据进行过滤

​ where是在分组前对数据进行过滤

  1. having后面可以使用分组函数(统计函数)

​ where后面不可以使用分组函数。

WHERE是对分组前记录的条件,如果某行记录没有满足WHERE子句的条件,那么这行记录不会参加分组;而HAVING是对分组后数据的约束。

LIMIT

LIMIT用来限定查询结果的起始行,以及总行数。

select * from emp limit 3,10;

3代表起始行为3; 10代表行数 (从第三行开始往下10行)

重要点:

1.使用统计查询时(存在GROUP BY子句),SELECT子句之中只允许出现统计函数与分组字段,其它的任何字段都不允许出现。

2.统计函数单独使用时(没有GROUP BY子句)只能够出现统计函数,不能够出现其它字段

3.此错误的意思就是where子句中不能使用组函数,因为where子句是在group by子句之前先执行的,所以在sql中要想给分组后的内容进行筛选则要依赖与having子句。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值