总结:
Map集合的基本功能以及遍历:
基本功能:
//添加键值对(如果键重复,后面的值会被覆盖)
v put(K key , v value);
//判断是否包含指定的键
boolean containsKey(Object key);
//判断是否包含指定的值
boolean containsValue(Object value);
//判断集合是否为空
boolean isEmpty();
//删除Map集合中的键,返回该键对应的值
V remove(Object key);
//获取Map集合中所有值得集合
Collection<v> values():
//清空Map集合
void clear();
遍历:
方式一(推荐的方式):
获取Map集合中所有键的集合,增强for遍历所有的键,通过键获取值;
Set keySet()—>获取Map集合中所有键的集合
V get(Object key)---->通过键获取值
方式二:(不推荐)
获取所有键值对像Set<Map.Entry<K,V>> entrySet()
Map.Entry<K,V>键值对像就有
K getKey():获取键
V getValue(): 获取值
//代码示例(方式一遍历)
public class MapDemo2 {
public static void main(String[] args) {
//创建Map集合
Map<String,String> map = new HashMap<>() ;
//添加元素
map.put("杨过","小龙女") ;
map.put("郭靖","黄蓉") ;
map.put("令狐冲","岳莹莹") ;
map.put("陈玄风","梅超风") ;
map.put("刘备","大乔") ;
map.put("刘备","小乔") ;
// Set<K> keySet()--->获取Map集合中所有的键的集合
Set<String> set = map.keySet();
//遍历所有的键
for(String key:set){
//V get(Object key)------->通过键获取值
String value = map.get(key);
System.out.println(key+"="+value);
}
}
}
TreeMap集合:
TreeMap<K,V>,集合也是Map集合的子实现类之一,TreeSet集合依赖于TreeMap实现
该集合保证元素必须进行排序的,使用TreeMap<K,V>,如果是自定义类型,要保证唯一而且还要排序,底层是一种红黑树结构;
//两种排序方式(构造方法)
//自然排序
public TreeMap():自然排序,键的这个类型必须实现Comparable接口
//比较器排序
Public TreeMap(Compator<K> comparator):定义一个类实现Compator接口或者使用匿名内部类
//完成自然排序
public class Student implements Comparable<Student> {
private String name ; //姓名
private int age ; //年龄
public Student() {
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//重写CompatorTo(Studen s)
@Override
public int compareTo(Student s) {
按照学生的年龄从小到大排序
int num = this.age - s.age ;
//年龄相等,不一定是同一个人
int num2 = (num==0)?this.name.compareTo(s.name):num ;
return num2;
}
}
比较器排序示例:
匿名内部类
*/
public class TreeMapDemo {
public static void main(String[] args) {
//TreeMap<Student,String>: K:学生类型 ,V: 爱好 String类型
//按照学生的年龄从小到大排序
//接口匿名内部类的方式
TreeMap<Student,String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
//主要条件:按照年龄从大到小
int num = s2.getAge()-s1.getAge() ;
//年龄相等,比较姓名内容是否一致
int num2 = (num==0)?s1.getName().compareTo(s2.getName()):num;
return num2;
}
}) ;//比较器排序
java中的自动拆装箱:
定义:
自动拆装箱分为拆箱和装箱:
拆箱:把包装类转换成对应的基本数据类型
装箱:就是将基本数据类型转换成对应的包装类类型
原理:
1)valueOf():所有的包装都有多个相同的方法,其中有一个为valueOf();这个方法就是将基本数据类型转换成对应的包装类类型,也可以使用包装类的构造方法直接转换;
2) xxxValue(),其中xxx代表8大基本数据类型,该方法就是将包装类类型转换成对应的基本数据类型
应用:
1)集合
集合是不接受存放基本数据类型的,但是在实际开发中一个Integer类型的集合是可以直接add一个int变量的,在这个过程就是自动装箱;
List<Integer> list = newArrayList<>();
int i= 1 ';
list.add(i); //着一步直接完成自动装箱
实际过程是list.add(Integer.valueOf(i);
2)比较
我们经常使用包装类与基本数据类型进行比较运算,得到一个布尔值,再进行不同的业务逻辑,这个过程是先将包装类转换成基本数据类型再进行比较大小
3)运算
两个包装类进行四则运算时,会将包装类转换成基本数据类型再进行运;
问题:
包装类自动拆装箱的时候也要注意:
1)有些场景会自动进行拆装箱,由于自动拆箱,如果包装类对象为null,那么那么自动拆箱是就可能抛出NPE(空指针异常)
2)如果一个for循环中有大量拆装箱操作,会浪费很多资源
3)包装类进行比较,在-128- 127可以用 == ,这个范围之外需要使用equals进行比较,因为包装类存在静态缓冲区范围为-128 - 127 ,所以在不明确范围的时候避免出现异常,最好使用equals方法比较
扩展:
基本数据类型对应的包装类类型:
byte -----------> Byte
short -----------> Short
int -----------> Integer
char ------------> Character
long ------------> Long
boolean ----------->Boolean
double -------------> Double
float ---------------> Float
静态导入:
jdk5提供的新特性:
增强for循环,自动拆装箱,静态导入(导入方法的级别,前提是这个类的方法是静态的),可变参数(方法的形式参数有多个可以使用...表示多个参数)
静态导入:
导入方式:import static包名.类名.静态方法名:
注 意:
如果我们在使用静态导入的时候,导入方法级别,前提是自定义的方法名不能和他冲突,如果冲突,系统就不知道这个方法是自定义的还是jdk提供的这个类的方法,此时静态导入就不能用了,所以就需要显示的指明是哪个类
mport static java.lang.Math.abs ; import static java.lang.Math.max; import static java.lang.Math.random; public class Demo { public static void main(String[] args) {
//静态导入(导入方法的级别,前提是这个类的方法静态的) //java.lang.Math:针对数学运行的工具类
//public static int abs(int a):求一个int类型的绝对值 System.out.println(Math.abs(-10)); System.out.println("--------------------------------"); //为了书写更简单,这个类是java.lang包下不需要导包,但是每次使用方法的 时候比较麻烦,类名.方法名() //优化:jdk5提供静态导入
// System.out.println(abs(-100)); System.out.println(java.lang.Math.abs(-100));
//指明 :使用的Math类的 abs方法
//获取最值public static int max(int a,int b) System.out.println(max(10,20)); int num = (int) (random()*10+1);
System.out.println(num); } public static int abs(int a){//方法名 abs return a;
} }
进程和线程的概念:
线程是依赖于进程的:
1)进程是能够调用系统资源的独立单元,通过任务处理器查看到后台进程有哪些
多进程的意义:
现在计算机都是多进程的,可以打游戏的同时,再听音乐:这两个进程是同事的吗? 并不是,其实多个进程在内存中不断进行高效切换,感觉是同时进行的(多进程是为了提高CPU的使用率)
2)线程:
是进程中的最小执行单元!一个线程就相当于一个进程中的某个任务
Jvm是多线程的吗?(面试题)
Jvm(java虚拟机)是多线程的,至少有两条线程
main --- 主线程(用户线程)
还有不断地创建对象,new.....堆内存中的信息需要被gc()垃圾回收器回收线程,帮助程序员,回收美有更多引用的对象,释放空间
java能够直接开启多线程吗?(面试题)
Java不能直接开启多线程,线程是依赖于进程存在的必须有进程才能有线程!
而创建进程----->需要创建系统资源,java语言不能直接创建系统资源的,只有C语言底层语言才能够操作系统资源,最底层的还是非java语言实现的,只是jdk为了使用方便将一些操作线程的东西方在了Thread类中,但是里面的非部分功能也是非java语言实现的
start()---->开启线程的方法,底层依赖于start()----被native修饰:非java 语言实现的(表示本地方法----跟系统相关的)
1,实现线程的创建方式第一种:(继承关系)
实现步骤
1)自定义一个类,继承自Thread(jdk提供的线程类)
2)在自定义的类中重写Thread类的run方法
3)在main线程(主线程,或者用户线程 )创建当前自定义类对象------->就是线程对象,启动线程即可
//资源类
public class myThread extends Thread {
//重写run方法(Thread类也实现了Runnable接口)
public void run(){
//线程需要运行的复杂代码
}
}
//测试类
public class Test{
public static void main (String[] args){
//创建资源类对象
MyThread mt = new MyThread();
//创建线程
Thread th = new Thread(mt);
//启动线程
th.start();
th.join(); //该线程执行,其他线程等待,知道该线程结束,其他线程再次竞争CPU资源
}
}
2.创建线程的另一种方式(实现Runnable接口的run方法,推荐使用的)
理 念:
体现了数据共享的概念,谁实现了Runnable接口的run方法,谁就是资源类(多个线程必须同时操作同一个资源)
该方式能体现出"资源共享的概念",使用到了代理模式中的静态代理模式
实现步骤:
1)自定义一个类实现Runnable接口,实现里面的Run方法
2)在主线程main,创建Runnable接口实现类--就是资源类对象,在创建Thread类对象,使他完成public Thread(Runnable target , String name),在/Thread构造方法中将资源类对象作为参数传递!
3)启动线程start
public final void setName()://给线程设置名字
public final void getname()://获取线程名字
public final void join()://线程礼让,等待某个线程终止,才能执行其他线程抢占,本身会抛出异常
public static void yield();//暂停当前正在执行的线程,并执行其他线程,让多个线程更和谐,(并不能完全保证)
```java(示例)
//资源实现类
public class MyRunnable extends Runnable{
//重写run()方法
public void run(){
//耗时操作
//获取正在执行的线程名字
System.out.println(Thread.currentThread().getName());
}
}
public class test{
public static void main(String[] args){
//创建资源实现类对象
MyRunnable mr = new MyRunnable();
//创建线程对象
Thread th = new thread(mr,"T1");
}
}
3,Thread类的常量表
public static final int MAX_PRIORITY 10 //最大优先级
public static final int MIN_PRIORITY 1 //最小优先级
public static final int NORE_PRIORITY 5 //默认优先级
注意:线程的优先级越大只能说他抢占CPU的几率越大,并不具有绝对性,线程的执行具有随机性
4.)线程的生命周期,有几种状态?(面试题)
Thread类的内部枚举 类型:
public enum State{
规定了六种状态
NEW,新建
RUNABLE ,运行状态
BLOCKED ,阻塞状态
WAITTING,等待(一直等待)
TIMD_WAITTING,超时等待
TERMINATED ,终止死亡状态
}
5.java中有23 中设计模式(思想):
分为三大类:
1) 创建型设计模式:(整个对象的创建):单例模式(重点),静态工厂方法(模式),工厂方法模式(重点)
2)结构型设计模式:(整个结构组成:抽象类,接口,具体实现类...) --->代理模式(重点)静态,动态代理
3)行为型设计模式(功能型设计模式:使用具体的应用场景):适配器模式,装饰着模式(IO流中使用)
6.检验多线程安全问题的标准------多线程安全问题的解决思路
1)首先检查你的程序是不是多线程环境 ?
2)你的程序中是否有共享数据 ?
3)你的程序中是否存在多条语句对共享数据进行操作 ?
解决方案:
java提供了一个同步代码块将对数据操作的代码部分包裹起来,解决线程安全问题(同步锁)
同步锁
synchronized(锁对象){
多条语句对共享数据的草做;
}
注意:锁对象可以 是任意java类型,但是,必须是同一类型;(锁只能有一个)
//如果一个方法中有同步代码块,可以将synchronized提到方法声明上 此时锁对象是this(这是针对非静态的方法),如果是静态的那就是当前类字节码对象 ,类名.class 属性
面试题:(锁对象问题)
1)同步方法的锁对象是谁呢? (一般说的都是非静态的)
非静态同步方法的锁对象是 this:代表当前类对象的地址引用
2)静态的同步方法的锁对象是谁呢?--->静态的东西和类相关
跟反射有关系,是当前类的字节码文件对象
之前讲Object类---->Class getClass():获取字节码文件对象 方式1
任意java类型的class属性(内置属性)--->第二种方式获取字节码文件对象
7.死锁问题:(两个线程互相等待)
死锁的产生:
在多线程的环境下,首先考虑的是线程安全问题,解决线程安全问题,使用同步代码块(同步机制,synchronize代码块),虽然解决了安全问题,但是降低了执行效率,可能产生一种"死锁"现象
解决方案:
使用等待唤醒机制
java Object 类提供了 线程等待 wait()方法,线程等待, 以及唤醒方法 notify() ,线程唤醒机制
8 为什么wait这些方法以及notify都在Object类中,而没有在Thread类中
因为这些方法都是跟锁对象有关系,而锁对象可以是任意java类型-----所以就定义在了Object类中
这两个方法都由锁对象调用,wait执行完后会主动释放锁,notify,会唤醒下同步等待的线程
9,同步机制解决线程安全机制(3个方法)
1)synchronize(锁对象 ){
同步代码块;
}
2)wait()和notify()
3)volatile :同步解决安全问题(不常使用)
10,线程池的使用:
1)创建线程池
Executors:工厂类(提供专门创建线程池的静态方法)public static ExecutorService newFixedThread(int nThread)
解释:创建一个线程数固定的线程池,返回值是一个接口---->底层源码---->肯定返回的接口的子实现类对象
2)提交异步任务:
ExecutorService :线程池--- 接口里面的方法都要被子实现类ThreadPoloolExecutor:实现
<T> Future<T> submit(Callable<T> task),提交异步任务并返回结果
3)关闭线程池
void shutdown():关闭之后不会接受任何新任务
10.1线程池的几个重要参数:(重点面试题)
1)corePoolSize:线程池中的核心线程数
2)maximumPoolSize:最大线程数,此值大于等于1
3)KeepAliveTime:空闲线程的存活时间
4)workQueue:任务队列
5)handle:线程池中的拒绝则略(当工作线程数大于等于最大线程数时如何拒绝请求执行的runnab的策略)
6)threadFectory: 表示生成线程池中工作的线程工厂
10.2面试题sleep()线程睡眠和线程等待wait()的区别:
1)来源不同 sleep(时间毫秒值) 来自于Thread类中--->是线程的方法 wait()来自于Object类中,是锁对象调用的
2)是否释放锁 sleep(时间毫秒值) 只是线程睡眠,睡眠时间到了,继续执行线程,调用这个不会是否锁 wait()方法是被锁调用的,线程在等待,会立即释放锁,只有释放锁,才能通知(唤醒)对方 线程
3)共同点:都是会抛出异常 当线程睡眠被中断或者线程等待被中断,就会抛出InterruptedException中断异常
public final void wait() throws InterruptedException public static void sleep(long millis) throws InterruptedException
10.3线程的生命周期有几种状态:
1)NEW 创建线程
2)RUNNABLE 运行
3)BLOCKED , 阻塞状态
4)WAITTING ,等待(一直等待)
5)TIMED_WAITTING ,超时等待
6)TERMINATED ,终止死亡状态
11.final 和 finally 有什么区别?(面试题)
单词前缀是一样的,都是关键字;
final : 是状态修饰符,表示最终的,无法更改的 ;
修饰类该类不能被继承,修饰方法该方法不能被重写,修饰变量此时变量是一个常量
finally: 不能单独使用,捕获异常的标准格式
处理异常:
throws 抛到方法上(不常使用),捕获具体的 异常信息,使用try --- catch---
标准书写:
try{
//可能出现问题的代码块
}catch{
//处理异常
}finally{
finally中的代码一定会执行的
释放资源(IO流中和连接池中经常使用)
}
变形格式:
try-----catch--catch---捕捉多个异常
try----finally----没有异常的语句
11.IO流以及分类:
** IO流概述:在不同设备之间进行数据的传送**
1)按流的方向分:
输入流: 读
输出流: 写
2)在流的方向上继续按类型分:
字节流:(抽象类:InputStream)
字节输入流: 读 具体类 FileInputStream
字节输出流: 写 具体类 FileOutputStream
字符流:(抽象类:Reader)
字符输入流: 读 具体类 InputStreamRander
字符输出流: 写 具体类OutputStreamRander
读写过程:
一次一个字节(字符)一个字节(字符)读取 比较慢 ,不推荐
一次一个字节数组(字符数组)一个数组的读,快捷,开发中比较推荐
IO流中的两个细节:
1)字节读入写出时候的换行 write(“/r/n”);
2)
**字节输入输出流
: 基本类FileInputStream和FileOutputStream的使用(标准写法)
public class FIleOutputDemo {
public static void main(String[] args) {
//创建字节输入输出流对象(第一步)
FileOutputStream fos = null;
FileInputStream fis = null ;
try {
//创建字节输出流对象
fos = new FileOutputStream(".txt");
fis = new FileInputStream("数据源路径");
// 读写数据(第二步)
//使用方式二 一次读写一个字节数组
byte[] bytes = new byte[1024]; //1kb = 1024b;
int len = 0 ;
//循环读写
while((len = fis.read(bytes) )!=-1){
fos.write("国庆节快乐".getBytes());
fos.write("\r\n".getBytes()); //字节中换行操作
//或者
fos.write(bytes, 0 ,len );
//刷新缓存(第三步)
f0s.flush();
}
//释放系统中的流对象资源资源 (必须手动关闭)第四步
} catch (IOException e) { e.printStackTrace();
}finally {
if (fos!=null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
} }
**/ 高效字节缓冲输入流和字节缓冲输出流的使用: BufferInputStream和BufferOutputStream的使用 **/
import java.io.*;
//高效字节流
public class BufferStreamDemo {
public static void main(String[] args) {
BufferedInputStream bis = null ;
BufferedOutputStream bos = null;
try {
//创建高效字节输入流对象
bis = new BufferedInputStream(new FileInputStream("g://练习.txt"));
//创建高效字节输出流
bos = new BufferedOutputStream(new FileOutputStream("CopyTest.mp4"));
//读写数据(一次读取一个字节数组)
byte[] bytes = new byte[1024];
int len = 0;
while((len =bis.read(bytes)) != -1){
bos.write(bytes,0,len);
bos.flush(); //释放前刷新缓冲区
//刷新缓冲区
bos.flush();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
//释放资源
if (bos!=null){
try {
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (bis!=null){
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
字符输入输出流:(抽象父类:Reader 和 Writer)
1) 基本子实现类:InputStreamReader(---解码过程)和OutputStreamWriter (---编码过程)不常使用 (代码繁杂)
2)便捷类:FileReader和FileWriter(经常使用)
3)高效字符缓冲流:BufferReader和BufferWriter(高效快捷,开发中经常使用)提供内部缓冲区,定义字符数组长度8192个长度
(注意);如果现在仅仅是键盘录入,可以使用Scanner或者StringBuffer(Reader in) 的 readLine()阻塞式方法,将内容存储在流中
//高效流
public class BufferReaderDemo {
public static void main(String[] args) throws Exception {
//创建高效字符输入流
BufferedReader br = new BufferedReader(new FileReader(""));
//创建高效字符输出流
BufferedWriter bw = new BufferedWriter(new FileWriter(""));
//读取数据(一次读取一个字符数组)
char[] chars = new char[1024] ;
int len = 0 ;
while ((len=br.read(chars))!=-1){
bw.write(chars, 0 ,len);
//刷新缓存
bw.flush();
}
//方式二:(bufferReader的特有功能) readLine() 行读取
String line = null ;
while((line = br.readLine())!= null){
bw.wait();
//特有功能 换行 newLine();
bw.newLine();
//刷新缓存
bw.flush();
}
//释放资源
bw.close();
br.close();
}
}
//基本类的使用代码实现
public class ReaderDemo {
public static void main(String[] args) throws Exception {
//创建字符转换输入流
InputStreamReader isr = new InputStreamReader(new FileInputStream(
"F://ideaObject//第三周测试//src//com//qf//Test_04//Animal.java"));
//创建字符转换输入流
OutputStreamWriter otw = new OutputStreamWriter(new FileOutputStream("CopyReader.txt"));
//读写数据
char[] chars = new char[1024];
int len = 0 ;
while ((len = isr.read(chars))!= -1){
otw.write(chars,0,len);
otw.flush(); //刷新
}
//释放资源
otw.close();
isr.close();
}
}
12,Properties:属性集合列表----和流有关系(重要)
属于map集合,但是没有泛型,键和值都只能是String类型,属于map,能够使用map集合功能,添加,遍历 等
但是他有自己特有的功能(推荐)
键和值都是String类型------>后期经常用到 xx.properties :作为配置文件,配置文件中的键和值都是String类型
key1 = value1
key2 = value2
......
.....
Properties的特有功能:
*添加元素,存储和去出不一致:
*public Object setProperties(String key ,String value)
//遍历:
*public set<String> stringPropertyName()获取所有键的集合
//通过键获取值
*public String getProperty(String key)
//两个高级功能
*将文件内容加载到属性集合列表中
*public void load(Reader reader) throws IOException ;
*public void load(InputStream inStream) throws IOException
**将文件内容输出到指定文件,并且给属性列表一个描述
*public void store(Writer writer ,String comments) throws IOException
参数二:针对属性列表的具体表述