Java笔记

本文主要介绍了Java中的网络编程基础,包括线程池和多线程概念,详细阐述了包与权限的管理,枚举的使用,以及常用类如StringBuffer和StringBuilder的解析。此外,还涵盖了基本数据类型包装类的作用,异常处理,集合框架,特别是List接口下的ArrayList和LinkedList,Set接口下的HashSet和TreeSet,以及Map接口的应用。最后,文章讨论了文件操作和IO流,包括字节流和字符流的相关知识点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

网络编程

B/S
C/S
数据是通过网络进行传输的

网络的基础
  网络模型:
     OSI:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
     TCP/IP:应用层(HTTP/数据)、传输层(分组,端到端/TCP、UDP,数据包)、网络层(路由、IP,数据帧)、网络接口层(010101)
        建立连接:经过3次握手
           1、客户端发送请求
           2、服务器响应,告诉客户端、我收到请求
           3、客户端发送确认请求 
        断开连接:经过四次握手
        提供的是可靠的数据传输。传输速度有限。端到端的数据传输。
		使用场景:传输的数据要求可靠。比如发送图片等文件
	
	UDP协议:无连接的。发送的数据,直接发,不管接收方是否收到的,也不确保收到的数据是否完全。
		不可靠。传输速度很快。支持一对一、一对多、多对多的数据传输。
		使用场景:对传输速度要求高,对结果不可靠影响不大的。比如腾讯会议
	
	IP:IP地址:网络上的主机的唯一标识
		IPV4:4个字节   172.16.10.115
		IPV6:16个字节
		
		域名:www.baidu.com---dns----xx.xx.xx.xx
	
	端口号:对软件的逻辑标识
		系统都会默认分配一个端口号
		程序也可以自己指定端口号
		0-65535 0-1024已被占用
		常用程序的端口号:MySql 3306 SqlServer 1433 Oracle 1521

软件-通过网络-软件

编程:jdk ---java.net	
TCP
	客户端
		Socket 此类实现客户端套接字(也可以就叫“套接字”)。套接字是两台机器间通信的端点
		        操作的是字节流
			Socket(String host, int port) 创建一个流套接字并将其连接到指定主机上的指定端口号。
			
			InputStream getInputStream() 返回此套接字的输入流。 
			OutputStream getOutputStream()  返回此套接字的输出流。
			void shutdownOutput() 禁用此套接字的输出流。  
				对于 TCP 套接字,任何以前写入的数据都将被发送,并且后跟 TCP 的正常连接终止序列
		
			void close()关闭此套接字。 
	服务端(应该先启动,否则客户端会报异常ConnectException)
		ServerSocket 此类实现服务器套接字。服务器套接字等待请求通过网络传入
			ServerSocket(int port) 创建绑定到特定端口的服务器套接字。此方法在连接传入之前一直阻塞。
			Socket accept() 侦听并接受到此套接字的连接。 
				服务器端没有自己的字节流,那怎么用?他就用客户端的流和相应的客户端进行交互
				客户端-服务器   多-1
					A   input  output
					B   input output
					C   input  output
			void close() 关闭此套接字 
	
	文件上传
		Client--->Server
		Client
			C:\Users\86136\Desktop\img\1.jpg
			1、把文件读到内存 FileInputStream
			2、内存通过网洛传输到Server OutputStream
		Server	
			1、读Socket InputStream
			2、写入文件 FileOutputStream
	文件下载
		Client<---Server
		Server		
			C:\Users\86136\Desktop\img\1.jpg
			1、把文件读到内存 FileInputStream
			2、内存通过网洛传输到Client OutputStream
		Client
			1、读Socket InputStream
			2、写入文件 FileOutputStream

UDP

线程池

为什么要线程池?(容器,集合)
    1丶线程池,统一管理线程,减少创建线程,销毁线程的操作,线程的使用率就高
    2丶定时,定期执行一定的任务
 怎么使用?
     都在包java.util.concurrent
     顶级接口Executor执已提交的Runnable
            子接口ExecutorService
                       实现类:ThreadPoolExecutor
             接口ScheduleExecutorService
                        实现类:ScheduledTreadPoolExecutor
      工具类Executors
             创建线程池对象
             static ExecutorService newCachedThreadPool() 创建可缓存线程的线程池
             static ExecutorService newFixedThreadPool(int nThreads)   创建固定线程数的线程池
             static ScheduledExecutorService newScheduledThreadPool(int corePools
             static ExecutorService newSingleThreadExecutor() 创建单线程的线程池
package pool;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TestPool {
	public static void main(String[] args) {
		ExecutorService pool= Executors.newCachedThreadPool();//可缓存线
//		ExecutorService pool= Executors.newFixedThreadPool(3);//固定
//		ExecutorService pool= Executors.newSingleThreadExecutor();//单一
	    for(int i = 1 ;i <=10 ;i++) {
	    	pool.execute(new MyRunnable(i));
	    	try {
				Thread.sleep(60);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
	    }
	    
	}
}

public class MyRunnable implements Runnable {
	int num;

	public MyRunnable(int num) {

		this.num = num;
	}

	@Override
	public void run() {
		System.out.println(Thread.currentThread().getName() + " ");
		try {
			Thread.sleep(100);
		} catch (InterruptedException e) {

			e.printStackTrace();
		}
	}

}

package pool;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class TestSchedulePool {
	public static void main(String[] args) {
		ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
		System.out.println("开始执行");
		pool.scheduleWithFixedDelay(new MyRunnable(1), 1, 3, TimeUnit.SECONDS);
		try {
			Thread.sleep(50);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}
}
       自定义线程池对象
               public ThreadPoolExecutor(int corePoolSize, 核心线程数
                          int maximumPoolSize, 最大线程数
                          long keepAliveTime, 最大空闲时间
                          TimeUnit unit,最大空闲时间 使用的单位
                          BlockingQueue<Runnable> workQueue,阻塞队列,等待的队列
                          ThreadFactory threadFactory, 线程工厂 ,创建线程
                          RejectedExecutionHandler handler)拒绝策略

多线程

进程:一个应用程序的实例。当我们启动一个应用程序的时候,就创建该程序的实例,其实开启了一个进程
    就会分配内存,硬盘,摄像头等等这些电脑资源
    进程是资源分配的基本单位

线程:运行在进程之中。进程中可以开启线程。
    一个进程中至少一个有一个线程,通常叫做主线程。main方法就是主线程的入口。
    一个进程中可以有多个线程,除了主线程之外,其他的线程都是有主线程创建的
        玩游戏:1丶游戏 2丶背景音乐 3 丶聊天 4 丶得分
            用户的感觉,多个线程在同时进行---实际上,-交替进行
    线程是CPU进行调度/运行的基本单位         
              
    多线程的好处:医生看病  张医生 1234567
        1丶CPU的利用率比较高
        2丶用户的体验好
        3丶简化开发
        
    多线程的实现:
        创建线程丶开启线程
        java.lang.Tread
        
        (一)**一种方法**是将类声明为Thread的子类。该子类应重写Thred类的run方法
            run()---线程体,在其中描述线程要执行的任务
            start()---使该线程开始执行;Java虚拟机调用该线程的run方法
            多线程交替运行的结果:交替的获取CPU的时间片

            (二) **另一种方法**是声明实现Runnable接口的类,该类然后实现run方法
             比较:1丶前者通过继承
                               简单
                               继承是单继承--局限
                         2丶后者是通过接口,重写run方法
                                接口时可以多实现--灵活
                                实现资源共享

在这里插入图片描述

线程的调度:如何去给多个线程分配CPU
                      是个复杂的过程,外界环境的干扰
                      影响CPU调度的因素
                      1丶优先级  1- 10之间数字  默认值是5
                                          获取CPU的概率会高
                       
                       2丶   Thread.sleep(毫秒);休眠
                                调用此方法,该线程会进入休眠状态,(阻塞),当休眠时间结束,线程继续运行                
                                可能引发InterruptedException
                                使用场景:模拟任务消耗的时间
                       3丶 join()加入,插入,插队
                                          实例方法,谁调用谁插队,等t线程执行完,其他线程才执行
                                          可能引发InterruptedException
                        4丶Threa.yield() 礼让
                               该代码所在线程礼让
                               放弃本次抢占到的时间片,重写进入下一次的抢占,可能礼让成功,也可能礼让不成功                
package c;
public class Test {
	/*
	 * 模拟医生看病的过程
	 * 
	 * 普通号50个
	 * 专家号10个  用时是普通号的2倍  优先级比普通号高
	 * 
	 * 等普通号看到第10个时,等所有的专家号叫完,再叫普通号
	 * 
	 * --->>主线程做普通号,自定义线程做专家号
	 */
	public static void main(String[] args) {
		Thread t = new Thread(new Special());
		t.setPriority(8);
		t.start();

		Thread main = Thread.currentThread();
		main.setPriority(2);
		for (int i = 1; i <= 50; i++) {
			System.out.println("----普通号:" + i);
			try {
				Thread.sleep(100);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

			if (i == 10) {
				try {
					t.join();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
package c;
public class Special implements Runnable {

	@Override
	public void run() {
		for (int i = 1; i <= 10; i++) {
			System.out.println("专家号:" + i);
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}

	}

}
-----------------------------------------------
package d;

public class Test {
/*
 * 模拟火车站卖票
 *  ticket
 *  多个窗口在卖
 *        多个窗口可以用多个线程来模拟
 *        卖票  -- 任务是一致
 *            多个窗口共享10张ticket
 *            
 *  问题:1.多个窗口卖出了同一张票
 *       2.有些票没人卖
 *       
 *       -----读写不一致
 *       多线程共享资源的时候,才可能引发
 * 
 *解决方案:
 *  加锁--把读写作为一个整体加锁
 *        synchronized(对象锁){
 *        
 * 
 */
	public static void main(String[] args) {
		SellTicket ticket = new SellTicket();
		
		Thread window1 = new Thread(ticket,"窗口1");
		Thread window2 = new Thread(ticket,"窗口2");
		Thread window3 = new Thread(ticket,"窗口3");
		window1.start();
		window2.start();
		window3.start();
		
	}
}

package d;

public class SellTicket implements Runnable {
	int ticket = 10;
	int num = 0;

	@Override
	public void run() {
		while (ticket > 0) {
			synchronized (this) {
				// 1.修改数据
				ticket--;
				num++;
				
				//时间差
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				
				// 2.出票
				System.out.println(Thread.currentThread().getName()+"卖出第" + num + "张票,剩余" + ticket + "张票");
			}

		}

	}

}

多线程共享资源,会引发数据不一致的问题
解决方案:
         加锁--把读写作为一个整体加锁
         同步代码块
                 synchronized(对对象锁){        }
                          每一个对象都有唯一的一把锁
         同步方法
                 一个方法内部只有一个同步代码块,那么我们经常写成同步方法,也就是把synchronized加在方法上

     两者的区别:
             1丶一个方法内部可以出现多个同步代码块,同步代码块可以嵌套
             2丶一个线程在访问同步方法,其他线程都不能访问所有的同步方法,只能访问非同步的方法
             3丶同步代码块更灵活,同步方法可以重用
      同步特点:
             1丶线程安全(多线程访问下,数据是正确的)
             2丶效率低(不提倡把耗时的操作加同步)
         编程的原则: 正确第一,效率第二
线程安全相关的类
         StringBuilder   非线程安全:效率高,适合单线程
         StringBuffer 线程安全的:效率低,适合多线程
 
		 HashMap   非线程安全  key可以null
		 Hashtable  线程安全  key不能为null
 
		 ArrayList 数组列表  非线程安全
		 Vector   向量  线程安全
		 ——————————————————
		 死锁
		            在多线程中,每个线程都拥有对方想要的锁,同时又等待对方给他锁

                    小花  拿着洋娃娃 --你把你的小汽车给我,我就把我洋娃娃给你
			         小明  拿着小汽车--你把你的洋娃娃给我,我就把我小汽车给你
			
		 死锁在程序中的表现:卡死了。
		 解决方案:使用外力。
		原因:同步代码块的嵌套 
			       同步代码块可能产生死锁,但不是一定产生死锁
package e;

public class Test {
	public static void main(String[] args) {
		Thread t = new Thread(new Xiaoming());
		Thread t1 = new Thread(new Xiaohua());

		t.start();
		t1.start();
	}
}

package e;

public class Xiaoming implements Runnable {

	@Override
	public void run() {
		synchronized (Toy.car) {
			System.out.println("小明玩小汽车");

			try {
				Thread.sleep(500);
			} catch (InterruptedException e) {

				e.printStackTrace();
			}
			synchronized (Toy.yww) {
				System.out.println("小明想玩洋娃娃,玩到了");
			}
		}

	}

}


package e;

public class Xiaohua implements Runnable {

	@Override
	public void run() {
		synchronized (Toy.yww) {
			System.out.println("小花拿到洋娃娃了");

			try {
				Thread.sleep(0);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			synchronized (Toy.car) {
				System.out.println("小花想玩小汽车呢");
			}

		}

	}

}

public class Toy {

	public static final Object car = new Object();
	public static final Object yww = new Object();
}

上述代码产生了死锁,改进如下代码,创建同一个对象,注意不要new

package e;

public class Test {
	public static void main(String[] args) {
		Object yww= new Object();
		Object car = new Object();
		Thread t = new Thread(new Xiaoming(car,yww));
		Thread t1 = new Thread(new Xiaohua(car,yww));

		t.start();
		t1.start();
	}
}

package e;

public class Xiaoming implements Runnable {
	private Object car;
	private Object yww;

	public Xiaoming(Object car, Object yww) {
		this.car = car;
		this.yww = yww;
	}

	@Override
	public void run() {
		synchronized (car) {
			System.out.println("小明玩小汽车");

			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {

				e.printStackTrace();
			}
			synchronized (yww) {
				System.out.println("小明想玩洋娃娃,玩到了");
			}
		}

	}

}


package e;

public class Xiaohua implements Runnable {
	private Object car;
	private Object yww;

	public Xiaohua(Object car, Object yww) {
		this.car = car;
		this.yww = yww;
	}

	@Override
	public void run() {
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		synchronized (yww) {
			System.out.println("小花拿到洋娃娃了");

			synchronized (car) {
				System.out.println("小花想玩小汽车呢");
			}

		}

	}

}

	     ————————————————————
	     生产者和消费者的问题
	     生产者生产,消费者消费
	     规则:先生产再消费,生产后即消费,消费完后再生产。按需生产,生产则消费
	                                生产-消费-生产-消费-生产-消费
		                            wait();//等待,等待当前对象调用notify或者notifyAll,否则就出于阻塞状态
		                             notify();//唤醒当前对象,解除阻塞            
package f;

public class Test {
	public static void main(String[] args) {
		Production pro = new Production();
		Thread p = new Thread(new Productor(pro));
		Thread c = new Thread(new Consumer(pro));
		p.start();
		c.start();
	}
}

public class Productor implements Runnable {
	private Production pro;

	public Productor(Production pro) {

		this.pro = pro;
	}

	@Override
	public void run() {
		for (int i = 1; i <= 20; i++) {
			pro.set("名称" + i, "描述" + i);
		}

	}

}

public class Consumer implements Runnable {
	private Production pro;

	public Consumer(Production pro) {
		super();
		this.pro = pro;
	}

	@Override
	public void run() {
		for (int i = 1; i <= 20; i++) {
//		try {
//			Thread.sleep(100);
//		} catch (InterruptedException e) {
//			// TODO Auto-generated catch block
//			e.printStackTrace();
//		}
//		System.out.println(pro.getName()+" "+pro.getDesc());
			pro.get();
		}

	}

}

public class Production {

	private String name;
	private String desc;

	public String getName() {
		return name;
	}

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

	public String getDesc() {
		return desc;
	}

	public void setDesc(String desc) {
		this.desc = desc;
	}

	boolean flag = true;

	public synchronized void set(String name, String desc) {
		if (!flag) {
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		setName(name);

		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {

			e.printStackTrace();
		}

		setDesc(desc);
		flag = false;
		notify();

	}

	public synchronized void get() {
		if (flag) {
			try {
				wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		try {
			Thread.sleep(50);
		} catch (InterruptedException e) {

			e.printStackTrace();
		}
		System.out.println(getName() + " " + getDesc());
		flag = true;
		notify();

	}
}

包与权限

包相当于操作系统的文件夹
好处:

  1. 管理java文件的:方便寻找(包名+类名)、解决重名的问题
  2. 保护资源 (结合着访问控制符,来限定资源的访问)

包的使用 :

  1. 一般都用小写英文
  2. 见名之义 公司域名的倒写+ 【部门名称】+项目名称+模块 、用.分隔,不能以.开头
  3. www.taobao.com---- com.taobao+qianniu
    学生管理系统 com.openlab.student.entity

包的创建:

  1. new Package
  2. 创建类的同时创建包 com.openlab.student.util StudentUtil.java

包的声明:

  1. package com.openlab.student.entity;
  2. 必须位于类的第一行非注释语句

包的导入:

  1. import java.util.Scanner;–类的完全限定名
  2. import java.util.* --导入包下的所有java类,但是不会导入子包中的类
  3. 不同包下的资源相互使用,需要先导包
  4. 快捷键 ://代码提示 Alt+/
  • //导包 Ctrl+Shift+O
  • 导入的类重名,来自不同的包,需要显式的写出 :
  • java.util.Date dateUtil;
  • java.sql.Date dateSql

权限:

  1. public 共有的 类内部、同包、不同包
  2. protected 受保护的 类内部、同包、不同包的子类
  3. default 默认的 类内部、同包
  4. private 私有的 类内部(ok) 同包(否) 不同包(否)
  5. public>protected>default>private

枚举

enum

  1. 可以当成数据类型来用
  2. 管理一系列的常量(限定取值)

由来:

  1. 枚举出来之前都是拿class或者interface来组织管理常量—基本的数据类型
  2. 缺点:只要数据类型合适,就会编译通过,不考虑实际的业务,可能造成错误
    enum 限定取值
    本质是Enum的子类:不能再继承别的类
public final String name() {
        return name;
    }
    public final int ordinal() {//序号
        return ordinal;
    }
	自定义枚举
	public enum Role2 {
		ROLE_NOMAL,
		ROLE_VIP,
		ROLE_SUPER_VIP
	}
	可以当成数据类型来用
	private Role2 role;
	限定取值	
	user.setRole(Role2.ROLE_NOMAL);
	枚举值的比较  equals或者==都可以
	Role2 r=user.getRole();
	if(r==Role2.ROLE_SUPER_VIP) {
		System.out.println("超级用户。。。。。。。。。。。。");
	}else if(r==Role2.ROLE_NOMAL) {
		System.out.println("普通用户。。。。。。。。。。。。");
	}switch更方便
	switch(r) {//byte int short String(1.7+),enum
		case ROLE_SUPER_VIP:
			System.out.println("超级用户。。。。。。。。。。。。");
			break;
		case ROLE_NOMAL:
			System.out.println("普通用户。。。。。。。。。。。。");
			break;
		case ROLE_VIP:
			System.out.println("VIP用户。。。。。。。。。。。。");
			break;
	}

常用类解析

常用类 jdk给提供出来的一些类。
为什么要学习?我们直接用,不用重复造轮子。
怎么学?

  1. 如果静态的,类名.成员
  2. 不是静态的,怎么创建实例对象,哪些属性,哪些方法(方法名,参数列表,返回值–功能)
  3. 使用的层次----> 面向对象的思想
  4. 工具?javadoc注释----查看api帮助文档
  5. IDE --提示,注释

StringBuffer类、StringBuilder类

AbstractStringBuilder 父类 char[] value 可变的 自动扩容
StringBuffer类

  1. 线程安全的可变字符序列。synchronized 同步锁 线程安全—适合多线程
  2. 可变字符序列,一个类似于 String 的字符串缓冲区
  3. StringBuffer append(XXX) 往末尾添加
  4. StringBuffer insert(int offset, String str) 指定位置添加
  5. StringBuffer reverse() 反转
  6. String toString()

StringBuilder类

  1. 一个可变的字符序列。此类提供一个与 StringBuffer 兼容的 API,
  2. 但不保证同步 ,非线程安全—适合单线程
  • String 类 其值在创建之后不能更改,可以共享 本质 是char value[]
  • String str=“abc”; 内存的方法区有一个字符串常量池,先去判断常量池中是有"abc",如果没有,就创建一个,放在常量池中,把地址给str
  • String str2=“abc”; 如果有,直接把地址赋值给str2,str、str2共同指向同一个地址,这就叫共享。

同时,带来了一个问题。
str=str+“cba”; — “cba” 、重写开辟区域,存储新的对象"abccba"
str=str+",a";— “,a”、、重写开辟区域,存储新的对象"abccba,a"
“cba”、 ",a"中间对象,垃圾
所以,在需要频繁地修改字符串的内容的时候,不适合使用String类
String str=new String(“abc”);

基本数据类型包装类

基本数据类型(8)

  • 数值型:byte、short、int、long、float、double
  • 字符型:char
  • 布尔型:boolean
    基本数据类型都是存储栈中,栈中存储的就是值本身,赋值、参数传递的时候操作的也是值本身。
    Java是面向对象的,对象都有属性和方法,基本数据类型只有值,没有方法,不遵循面向对象。Java为了完善,为了提供更多的方法去操作基本数据数据,就提供出来了包装类

包装类:

byte— Byte
short—Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean
除了int–Integer、char–Character,其它的都是首字母变大小

包装类的继承关系
Object
–Number(abstract父类)
–Byte、Short、Integer、Long、Float、Double
–Character
–Boolean

Integer以此为例
public final class Integer extends Number implements Comparable
1、final 不能继承
2、extends Number 未继承很多功能
3、Comparable 可比较的 Arrays.sort()
public int compareTo(T o);
返回值:负数:小于 正数:大于 0:等于

属性 field
MIN_VALUE -2147483648 -2^31
MAX_VALUE 2147483647
TYPE 获取int类对象
SIZE = 32; int数据占32位
BYTES = SIZE / Byte.SIZE int数据占多少字节

程序中使用的话,直接用常量,可以节约资源

private final int value; 存储的就是Integer类的数据,本质上就是int value
value一旦赋值,不能更改,靠什么达到像String对象的共享?—稍后

	构造	
	Integer(int value) 
	Integer(String s)---要求s必须能转换成int,否则NumberFormatException: For input string: "a25"
	
	方法
	static int parseInt(String s)
	static int parseInt(String s, int radix) 就是把字符串转换成int ,radix进制可选
	不支持Integer.parseInt("0x10",16) 但是Integer.parseInt("10",16)
	------------------------------------------------------------------
	static Integer valueOf(String s) 、
	static Integer valueOf(int i)
	valueOf系列方法,把其它数据类型转换成当前类型
	
	
	public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }
    以上方法意思就是,如果传入的整数是-128-high之间的数,直接从缓存中返回对象。否则新创建
     原来,Integer类中有一个静态内部类  IntegerCache,内部类中有一个cache,当Integer加载的时候,就会初始化此类,缓存
  -128-high(一般就是127)之间的数。
  
  如果你需要Integer类型的对象,优先使用valueOf,而不是构造方法
  
   **其它包装类?**
  public static Float valueOf(float f) {
        return new Float(f);
  }
 Float、Double类的valueOf()没有缓存。为什么不呢?[-128-127] 整数数量是固定的,小数是无穷的。
  
  **Boolean类**
  public static final Boolean TRUE = new Boolean(true);
  public static final Boolean FALSE = new Boolean(false);
  
  总结:
  1、Byte、Short、Integer、Long的valueOf方法都有缓存,【-128,127】
  2、Float、Double的valueOf方法没有缓存,每次都会新创建对象
 3、Character 的valueOf方法 有缓存,【0,127】
 4、Boolean 的valueOf方法 有缓存,有静态的常量true,false,直接返回
 
 -------------------------------------
		
xxx(基本数据类型) xxxValue()  获取包装类中的基本数据类型的值 value

-------------
toString()
static String toString(int i)---建议看源码

------------
equals方法主要来判断值是否相等 
public boolean equals(Object obj) {
    if (obj instanceof Integer) {
        return value == ((Integer)obj).intValue();
    }
    return false;
}
Integer 中equals方法:当类型相同且值相等,才返回true

-----------------
进制间转换  把10进制的数转换成其它进制
static String toHexString(int i)  --16进制
static String toOctalString(int i) --8进制
static String toBinaryString(int i)--2进制

------
static int reverse(int i) 反转 不是这样的效果123---321

总结:1、数据类型转换
	int--String
		1)a+""
		2)String.valueOf()
		3)Interger:String toString(int i)
	String--int
		1)Integer.parse(String)
	
	Integer-String
		1)toString()
		
	String--Integer
		1)Integer valueOf(String s, int radix)
		2)Integer(String s)
	
	int--Integer
		1)Integer(int i)
		2)Integer valueOf(int i)
	Integer--int
		1)int intValue()
		
	2、进制转换
	------------------------
	
	
	装箱:基本数据类型--->包装类型  自动转换
	本质:Integer.valueOf()
	Integer i=12;
	Integer i2=Integer.valueOf(12);
	以上代码效果相同
	
	---
	Integer num1=12;
	Integer num2=12;
	System.out.println(num1==num2);//true
	说明num1和num2地址相同,因为num1和num2都是从缓存中取的同一个地址
	
	--
	Integer num1=129;
	Integer num2=129;
	System.out.println(num1==num2);//false
	129没有缓存,每次都需要重写创建,所以num1和num2地址不同
	--
	Double num1=12d;
	Double num2=12d;
	System.out.println(num1==num2);//false
	因为Double 没有缓存
	
	拆箱:包装类型--基本类型  自动转换
	本质:Integer.intValue()
	int num=i;//拆箱
	
	注意:如果可以的话,不要频繁地装拆箱
	
	什么时候装箱、拆箱?
	Integer num1=400;
	int num2=400;
	System.out.println(num1==num2);//true
	返回true就可以说明num1发生了拆箱操作。换一句话来说,==链接包装类和基本数据类型的时候,就拆箱
	
	Integer num1=400;
	int num2=400;
	System.out.println(num1.equals(num2));//true
	返回true就可以说明num2进行了拆箱  
	
	Long num1=400l;
	int num2=400;
	System.out.println(num1.equals(num2));//false
	原因:long类型的equals方法要求类型相同且值相同才返回true,而num2自身装箱成了Integer类型
	
	Integer num1=400;
	int num2=400;
	System.out.println(num1*num2);
	当+、-、*、/、%链接包装类和基本数据类型的时候,是拆箱
	
	
	拆箱的时候注意避免空指针异常
	Integer num1=null;
	int num2=num1;//java.lang.NullPointerException
	就是拆箱实际在执行intValue()
	

Character
	System.out.println(Character.isDigit('a'));
	System.out.println(Character.isLetter('a'));
	System.out.println(Character.isWhitespace(' '));
	System.out.println(Character.isUpperCase('A'));
	System.out.println(Character.isLowerCase('b'));
	System.out.println(Character.toLowerCase('U'));
	

BigInteger
	做权限控制
	BigInteger setBit(int n)  bi+2^n
	boolean testBit(int n)
BigDecimal

异常:

在程序编译或运行过程中出现的不正常的情况
从面向对象的角度来说,异常也是一个对象。如何描述一个异常?
异常名称:java.lang.ArithmeticException 
异常出现的原因:/ by zero
异常出现的位置:at Test.main(Test.java:5)

处理异常:
方式一:添加判断 if...else
	缺点:程序员会把精力放在避免异常,无法集中在业务上了。一直在不漏洞,但是也不一定能补全
		 业务代码被处理异常的代码淹没了,可读性不强
方式二:异常处理机制: 预置一些异常处理程序---如果异常情况---执行相应的处理程序,这样就不会让程序中断
小明上班 大约30分钟  ---正常
	堵车----迟到 ,处理措施:通知领导
	交通事故----处理措施:请假一天
	
	生活继续
具体怎么实现?通过以下几个关键字来实现的:try catch finally throws throw
try{
	////可能出现异常的代码
}catch(){
	//异常出现的话,如何处理---异常处理程序
}catch(){
	//异常出现的话,如何处理---异常处理程序
}
finally{
	//不管是否出现异常,都会去执行的代码
	//关闭资源 善后、收场
}

此结构中,try必选,catch和finaly可选,但是必有其一

正常情况:执行try,继续后续代码
异常情况:出现异常之后的代码不再执行,转到catch块执行,继续后续代码
		出现异常,系统会产生一个异常对象,会和catch块中捕获的类型匹配,匹配上才执行其中的代码,匹配不上就报错
		多种异常的话,我们可以使用多个catch语句来捕获。从上往下匹配,上面的匹配上,下面的就不再匹配
		所以,catch种捕获的异常类型应该从小到大来写,否则会报错,因为有些catch块永远也执行不了
		
		提问:
		1、直接一个父类异常把各种子类异常全部包含了。从而只写一个catch块行吗?
		可以的,只是不具体。不能清晰地去处理某一种具体的异常。
		2、如果某些异常的处理程序是一样的,可以用|来连接多个异常类型
		catch(InputMismatchException|ArithmeticException ex )


finally不管是否出现异常,都会去执行的代码
	return 无法阻拦
	当有return语句的时候,先执行return前的语句,再执行finally,最后return
	有没有可以阻拦finally执行的?有一个 ,System.exit(status),直接停掉JVM 
	status如果是0,表示正常退出。非0,表示异常退出。
	提问:
		如果之前return了然后执行 finally语句   finally语句里面也有有return 那么执行哪个return
	回答:
		最终是finally中的return起了作用
		一般编码中,不会同时出现。不建议这样写。

异常体系:
Throwable 
	Throwable 类是 Java 语言中所有错误或异常的超类。
	通过 Java 虚拟机或者 Java throw 语句抛出。
	只有此类或其子类之一才可以是 catch 子句中的参数类型
	 void printStackTrace()打印异常的堆栈信息 ---方便调试程序的
	 String ex.getMessage()获取异常的原因 ---方便调试程序的
  Error 严重的问题,合理的应用程序不应该试图捕获
  	我们程序不用关注这一类
  	合理的应用程序不应该试图捕获的严重问题
	OutOfMemoryError  内存溢出--堆内存
		int[] num=new int[1024*1024*1024];//.OutOfMemoryError: Java heap space
	StackOverflowError 栈溢出
		private static void func() {
			func();
		}
 Exception 一般问题,合理的应用程序想要捕获
 	RuntimeException 运行时异常,不强制要求程序处理
 		ArrayIndexOutOfBoundsException 数组下标越界异常
 		NullPointerException 空指针异常  --null对象调用属性和方法
 		InputMismatchException 输入不匹配异常
 		ArithmeticException 算术异常
 		ClassCastException 类型转换异常
 	除了RuntimeException及子类之外,编译时异常,外界的原因,强制要求程序处理
 		举例:
 		try {
			Class.forName("com.open.TestJava");//加载类
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
		
throws 声明异常  
	在方法声明后添加throws ClassNotFoundException:意思是 方法体中有可能会发生此类异常
	并没有真正处理,那么谁来处理?谁调用谁处理!
 		
 	什么时候用?就是可能出现异常的地方,不想或不能处理此异常,就选择声明异常。声明之后,会通过调用者逐层要求处理,最终道JVM停止。
	如果存在多个异常,是可以声明多个,用逗号分隔开

	运行时异常,不强制要求捕获或者声明。即使声明了,也不要求调用者必须捕获或者声明。所以,我们一般不声明,但是往往会捕获。
	编译时异常,强制要求捕获或声明。如果方法内部不捕获,那么调用者或者上层调用者就必须捕获。否泽,编译会出错。

	异常是要捕获还是声明?
	1、如果调用者的异常处理程序是一致的,我们就选用方法内部捕获
	2、还要考虑处理此异常的层级。
	
	重写中异常声明的问题:
	子类重写父类的方法,规则是:
		1、继承
		方法名相同
		参数列表相同
		返回值类型可以缩小
		访问控制权限可以放大
		声明的异常可以缩小
	重载:
		1、同一个类中
		2、方法名相同
		3、参数列表不同
		4、与返回值类型和访问控制权限无关
		
--------------------
throw 抛出异常
	throw 异常对象;
	
自定义异常
	如果是编译异常,可以直接继承Exception
	运行时异常,可以继承RuntimeException。或者意思的某个子类
	
	可以重写带参构造,设置异常原因。
	
	自定义异常只能手动抛出,不能让JVM抛。
	
综合案例:
	模拟老师用电脑的上课
	异常可以转换,转换的时候可以传递 -------在catch块中 throw new ClassInterruptException(e);
	com.teach.ClassInterruptException: com.teach.MaoYanException: 电脑猫眼啦
		at com.teach.Teacher.teach(Teacher.java:22)
		at com.teach.Test.main(Test.java:8)
	Caused by: com.teach.MaoYanException: 电脑猫眼啦
		at com.teach.Computer.start(Computer.java:18)
		at com.teach.Teacher.teach(Teacher.java:14)
		... 1 more

	
以后提问问题的时候:
	编译是否报错。---贴代码
	如果编译无误,运行报错。----贴代码 ,最好带上错误堆栈信息
	如果编译没错,运行也没报错,只是结果不理想。 ----业务逻辑的问题
	
日志记录	
	需要把异常的堆栈信息保存,不能只停留在控制台。从而更方便的定位错误
	日志:错误日志、正常的操作信息、SQL日志、业务日志
	
	一般使用的是Apache公司的开源项目log4j
	使用步骤
	 1、下载jar 包 --java的class文件的压缩包
	 2、添加jar包项目
	 3、配置文件  . propreties .xml  log4j.properties
	 	propreties 以键值对方式存储 key=value
	 4、代码中引用

集合

如果存储多个变量,可以使用数组。
数组特点:定长、存储的是同种类型 、存储单列数据
总结缺点:就是没有很多的增删改查、统计等等这样的方法。
学号—学生
科目号–课程信息
订单编号—订单信息

	映射关系 key---value
	
集合框架:一些接口和类。java.util包下
	学习方法:学习接口,使用实现类

	Collection 集合  单列集合的根接口
		一些 collection 允许有重复的元素,而另一些则不允许。
		一些 collection 是有序的,而另一些则是无序的
		JDK 不提供此接口的任何直接 实现
			List 列表
				有序、访问顺序和插入顺序一致
				有索引
				允许重复
				允许null 元素
				使用参考:动态数组
				
				ArrayList:可变长的数组
					此实现不是同步的,不是线程安全
					好处:	访问、修改速度快
					缺点:	添加、删除速度慢
						浪费空间
					使用场景:查询、遍历
						如果需要频繁增删,就不要考虑了
					
					
				LinkedList:双向链表
					随机访问效率低
					增删快
					
					
			Set 数据集,集合
				不包含重复元素
				最多包含一个 null 元素
				不要求有序
				参考:模仿了数学上的 set 抽象
				
				HashSet
				LinkedHashSet
				TreeSet
		
	Map 映射  --映射
	将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。 
		HashMap
		
	工具类:Collections

泛型 可以约束集合存储的数据类型
数据类型参数化
字母:E(element) K(key) V(value) T(type)
其实所有的字母都可以使用
适用的场景:泛型类、泛型接口、泛型方法
好处:扩展性好

集合Collection

List

使用:相当于动态的数组

允许重复,有序(访问顺序和插入顺序一致)
允许为null
有下标

ArrayList:

真正的动态数组,自动地扩容或缩容
线程不安全

底层实现:数组
特点:随机访问快、增删慢、要使用连续空间,空间利用率不高
使用场景:如果需要频繁地增删,不要使用

LinkedList:

底层实现:双向链表
特点:增删快,随机访问慢

作为List的实现类:ArrayList可以实现的功能,LinkedList都可以
作为Deque的实现类:

Deque:双端队列
	 void addFirst(E e);
	 void addLast(E e);
	 boolean offerFirst(E e);
	 boolean offerLast(E e);
	 E removeFirst();
	 E removeLast();
	 E getLast() 
	 E getFirst()
			 
	还可以作为栈来使用
	void push(E e);//给开头添加元素
	E pop();// 获取并移除开头的元素
	E peek();获取不移除开头的元素
			
	还可以作为普通队列使用
	boolean offer(E e);//给结尾添加元素
	E poll()// 获取并移除开头的元素
    E element() //获取不移除开头的元素
		
Vector 实现 list接口
			和ArrayList很像
			最大的区别就是,Vector是线程安全的
			在单线程下,就被ArrayList替代了
Stack 栈
	被LinkedList替代了

Set

模拟了数学的集合的概念
不允许重复
不要求有序
没有下标

HashSet

不允许重复
无序

	 * hashSet 无序 不重复
	 * 底层实现
	 * 1、jdk8之前  数组+链表
	 *   jdk8之后  数组+链表/红黑树
	 * 
	 *   当添加元素的时候
	 *   1)根据hashCode去分组----数组
	 *   2)  如果hashCode值相同(哈希冲突),去判断对象的值是否相同(equals)
	 * 			

TreeSet

	 	底层实现:红黑树--平衡二叉树
	 	有序的(不是插入顺序,自定义顺序)
	 	不重复

Map 关系、映射

Entry 实体	 Key  --  Value	  (一对一,多对一)
将键映射到值的对象
一个映射不能包含重复的键,键唯一
每个键最多只能映射到一个值
多列集合:Key的集合(Set),Value的集合(List),Entry集合

HashMap
	允许使用 null 值和 null 键

Collections 操作集合的工具类
Arrays 操作数组的工具类

File

File表示文件、文件夹
如果操作文件的内容,就需要用到流

流 --是内存和硬盘数据交互的一个通道/桥梁 java.io

按照数据的流向,把流分为
     输入流:文件-内存(读)
     输出流:内存-文件(写)
     站在内存角度上来理解
按照数据交互的单元来划分,可以分为  
     字节流:一次一个字节
     字符流:一次一个字符
     字符流最终还是以字节流方式实现的
 
     综合起来:字节输入流  字节输出流
                       字符输入流   字符输出流

字节流

字节输入流

 InputStream 此抽象类是表示字节输入流的所有类的超类。 
	       abstract  int read() 从输入流中读取数据的下一个字节. 返回值:下一个数据字节;如果到达流的末尾,则返回 -1。
	      int read(byte[] b)  从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中。
		           从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b 中 
		           读入缓冲区的总字节数;如果因为已经到达流末尾而不再有数据可用,则返回 -1。 
            int read(byte[] b, int off, int len) 将输入流中最多 len 个数据字节读入 byte 数组。 
            void close() 关闭此输入流并释放与该流关联的所有系统资源。 

FileInputStream 从文件系统中的某个文件中获得输入字节
	     FileInputStream(File file) 
	     FileInputStream(String name) 
BufferedInputStream	 在创建 BufferedInputStream 时,会创建一个内部缓冲区数组。
	BufferedInputStream(InputStream in)   创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 
	BufferedInputStream(InputStream in, int size) 创建具有指定缓冲区大小的 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。 

字节输出流

OutputStream 表示输出字节流的所有类的超类
	abstract void write(int b) 将指定的字节写入此输出流。
	void write(byte[] b)   将 b.length 个字节从指定的 byte 数组写入此输出流。 
	void write(byte[] b, int off, int len) 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。
	void close()  关闭此输出流并释放与此流有关的所有系统资源。 
	void flush()  刷新此输出流并强制写出所有缓冲的输出字节。
	
FileOutputStream 文件输出流是用于将数据写入 File 或 FileDescriptor 的输出流 
 	FileOutputStream(File file) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
 	FileOutputStream(File file, boolean append) 创建一个向指定 File 对象表示的文件中写入数据的文件输出流。
	FileOutputStream(String name) 创建一个向具有指定名称的文件中写入数据的输出文件流。 
 	FileOutputStream(String name, boolean append) 创建一个向具有指定 name 的文件中写入数据的输出文件流。 
BufferedOutputStream 该类实现缓冲的输出流
	BufferedOutputStream(OutputStream out) 创建一个新的缓冲输出流,以将数据写入指定的底层输出流。 
    BufferedOutputStream(OutputStream out, int size) 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流。 

不管是二进制文件还是文本文件,在内存都是以二进制的方式存储
字符串—byte[] 编码 就依赖一定的编码方式 不同的编码方式,存储方式不一样
字符流–转换 不管是字节流,还是字符流,最终都是以字节流的方式在处理的

字符输入流

 Reader 用于读取字符流的抽象类
   int read() 读取单个字符。 
   int read(char[] cbuf)将字符读入数组。 
   abstract  int read(char[] cbuf, int off, int len) 将字符读入数组的某一部分。 

	InputStreamReader 字节--->字符  字节流通向字符流的桥梁   
		 自带缓冲区  8192
		 可以自定义编码格式来解码
		InputStreamReader(InputStream in) 创建一个使用默认字符集的 InputStreamReader。
		InputStreamReader(InputStream in, String charsetName) 创建使用指定字符集的 InputStreamReader。
		FileReader 用来读取字符文件的便捷类。
			 FileReader(String fileName) 在给定从中读取数据的文件名的情况下创建一个新 FileReader。
			 FileReader(File file)在给定从中读取数据的 File 的情况下创建一个新 FileReader。
		BufferedReader 提高字符流的读取速度 
			 String readLine() 读取一个文本行。
			   包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 null 

字符输出流

Writer
 void write(char[] cbuf) 写入字符数组。 
 abstract  void write(char[] cbuf, int off, int len)写入字符数组的某一部分。 
 void write(int c)  写入单个字符。 
 void write(String str) 写入字符串。 
 void write(String str, int off, int len) 写入字符串的某一部分。 

	OutputStreamWriter 是字符流通向字节流的桥梁 字符--->字节
	   OutputStreamWriter(OutputStream out)  创建使用默认字符编码的 OutputStreamWriter。
	
		FileWriter 用来写入字符文件的便捷类。
			FileWriter(File file) 根据给定的 File 对象构造一个 FileWriter 对象。 
		    FileWriter(File file, boolean append) 根据给定的 File 对象构造一个 FileWriter 对象。 
		    FileWriter(String fileName) 根据给定的文件名构造一个 FileWriter 对象。 
			FileWriter(String fileName, boolean append)  根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。 
		BufferedWriter   提高字符流的写入速度  
			void newLine() 写入一个行分隔符。 

思路:
1、字节 Stream ?还是字符? Reader/Writer
2、流向:输入input reader?输出? output writer
3、如果需要指定编码格式去转换字节–字符,转换流 InputStreamReader,InputStreamWriter
4、是否需要提高速度?Bufferedxxx

IO流

字节流
字符流

操作二进制文件,操作java基本数据类型 
DataInputStream  
DataOutputStream  

操作java任何数据类型,专门来操作Object对象
ObjectInputStream
   Object readObject() 从 ObjectInputStream 读取对象。 
ObjectOutputStream
   void writeObject(Object obj)  将指定的对象写入 ObjectOutputStream。 
         不能序列异常
 	java.io.NotSerializableException: com.data.Student
 	
序列化:java对象 ---->字节
实现方式一:实现Serializable接口 ,此接口只是一个标记,表名此类型的对象可以序列化
	1、也可以实现部分属性的序列化  ,不需要序列化的字段前面加上transient
	   不需要的情况:1、业务  2、自定义类型比较复杂,代价大
	2、自定义类型 序列化时,要求所有的非transient类型的属性都实现序列化
	3、父类实现了序列化,子类可以继承,无需再实现此接口
	4、静态的属性也是不序列化的,静态的内容是属于类的
实现方式二:实现Externalizable接口
	可以实现部分属性的序列化
作用:主要是方便存储对象,或者方便在网络间传输。
	
反序列化:字节---->java对象
readObject() 
可能会出现InvalidClassException,原因是因为serialVersionUID不一致了
serialVersionUID  识别序列化字节和内存中类的版本的
根据类中的属性和方法综合计算来的一个long值,也就是类中属性或者方法有改动,long值就会改变
serialVersionUID的作用:主要用在序列化列升级的时候(属性和方法有改动的时候)
	1)如果让当前版本兼容之前的版本,需要使用之前的序列号
	2)如果不想让当前版本兼容之前的版本,改变序列号
 作用:方便恢复/重建对象
 
Properties  集合
log4j 日志记录 .properties  键值对 xxx==xxx 
java中很常用的配置文件 properties/xml
Properties 类表示了一个持久的属性集。Properties 可保存在流中或从流中加载。
   	继承Hashtable<K,V>,Hashtable和HashMap类似,唯一的区别就是Hashtable是线程安全的
   	属性列表中每个键及其对应值都是一个字符串。
   	String getProperty(String key)
   	setProperty(String key, String value)
   	void store(Writer writer, String comments)
   	void store(OutputStream out, String comments)
   	void load(Reader reader)
   	void load(InputStream inStream)

System.in----InputStream  标准的字节输入流
System.out----PrintStream  print方法:以字符串的形式输出
          PrintWriter 以字符串的形式输出
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值