异常
try{
// 程序体
}catch(){
// 抛出异常
}finally{
// 不管成功还是失败都执行
}
- 简单的不写了
String对象
-
新建:
-
String s1 = new String(“111”); System.out.println("s1:" + s1);
字符串比较
-
== 比较基本数据类型:比较的是具体的值
-
== 比较引用数据类型:比较的是对象地址值
-
equals方法的作用:比较两个字符串内容是否相同、区分大小写
字符串遍历
- length()方法用户获取长度
- charAt() 用于取值
StringBuilder对象
-
区别:String类:内容是不可变的,StringBuilder类:内容是可变的
-
append()追加其实就是拼接字符串
-
reverse() 字符串反转
-
StringBuilder对象转String : toString()
ArrayList对象
-
其实就是对数组的二次封装
-
声明语法:ArrayList array = new ArrayList();
-
add() 方法,添加一个元素 get(n) 方法,获取第n号元素 remove(n) 方法 去除第n号元素 size() 方法,返回集合中元素的个数
面向对象
继承
-
因为子类中所有的构造方法默认都会访问父类中无参的构造方法
-
解决:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?
-
1. 通过使用super关键字去显示的调用父类的带参构造方法 2. 在父类中自己提供一个无参构造方法
关键字
-
extends 继承关键字
-
super 调用父类的方法和属性
-
Override注解,用来检测当前的方法,是否是重写的方法,起到【校验】的作用
-
子类方法访问权限不能更低(public > 默认 > 私有)
-
package 格式package 包名; (多级包用.分开)
-
import(理解)格式:import 包名;
参数传递
类名作为形参和返回值
-
1、类名作为方法的形参 //依赖注入 方法的形参是类名,其实需要的是该类的对象 实际传递的是该对象的【地址值】 2、类名作为方法的返回值 // 返回类的地址,也是该类的对象 方法的返回值是类名,其实返回的是该类的对象 实际传递的,也是该对象的【地址值】
抽象类作为形参和返回值
-
方法的形参是抽象类名,其实需要的是该抽象类的子类对象 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象
接口名作为形参和返回值
-
方法的形参是接口名,其实需要的是该接口的实现类对象 方法的返回值是接口名,其实返回的是该接口的实现类对象
常用系统类API
Math类
- Math 包含执行基本数字运算的方法
System 类
-
方法名 说明 public static void exit(int status) 终止当前运行的 Java 虚拟机,非零表示异常终止 public static long currentTimeMillis() 返回当前时间(以毫秒为单位) public class SystemDemo { public static void main(String[] args) { // 获取开始的时间节点 long start = System.currentTimeMillis(); for (int i = 1; i <= 10000; i++) { System.out.println(i); } // 获取代码运行结束后的时间节点 long end = System.currentTimeMillis(); System.out.println("共耗时:" + (end start) + "毫秒"); } }
Object类的toString方法
-
public static void main(String[] args) { Student s = new Student(); s.setName("林青霞"); s.setAge(30); System.out.println(s); System.out.println(s.toString()); }
类型包装类
-
基本数据类型 包装类 byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean
string跟Int相互转化
- int转换为String
- 方式一:直接在数字后加一个空字符串
- 方式二:通过String类静态方法valueOf()
- String转换为int
- 方式一:先将字符串数字转成Integer,再调用valueOf()方法
方式二:通过Integer静态方法parseInt()进行转换
- 方式一:先将字符串数字转成Integer,再调用valueOf()方法
字符串数据排序
-
split 字符串根据参数进行切割成新的数组
-
String strList = "90 56 100 45 60"; String[] strArr = strList.split(" "); int[] intArr = new int[strArr.length]; for (int y=0; y<strArr.length;y++){ intArr[y] = Integer.parseInt(strArr[y]); } Arrays.sort(intArr); System.out.println(Arrays.toString(intArr));
时间类
-
获取当前时间戳:System.currentTimeMillis(); 或者 Date d = new Date(); long time = d.getTime();
-
时间戳转规格时间:
-
SimpleDateFormat sdf = new SimpleDateFormat( "yyyy-MM-dd HH:mm:ss"); ystem.out.println(sdf.format(time));
-
规格时间转时间戳
-
// 格式时间转时间戳 try { Date times = sdf.parse(date); System.out.println(times.getTime()); } catch (ParseException e) { e.printStackTrace(); }
日历类
-
Calendar 提供了一个类方法 getInstance 用于获取这种类型的一般有用的对象
-
方法:get返回给定日历字段的值 add根据日历的规则,将指定的时间量添加或减去给定的日
历字段 set设置当前日历的年月日 -
// 获取任意一年的二月有多少天 //键盘输入年 Scanner sc = new Scanner((System.in)); System.out.println("请输入任意年:"); int year = sc.nextInt(); //创建日历类 Calendar c = Calendar.getInstance(); c.set(year,2,1); //3月1日往前推一天,就是2月的最后一天 c.add(Calendar.DATE, -1); //获取这一天输出即可 int date = c.get(Calendar.DATE); System.out.println(year + "年的2月份有" + date + "天");
- int转换为String
集合
- 提供一种存储空间可变的的存储模型,存储的数量可以随时发生改变
单列(Collection)
-
单列集合是集合的顶层接口,他表示一组对象,这些对象也称为Collection元素
-
声明方式:Collection c = new ArrayList<>();
-
没有索引
-
常用函数
-
方法名 说明 boolean add(E e) 添加元素 boolean remove(Object o) 从集合中移除指定的元素 void clear() 清空集合中的元素 boolean contains(Object o) 判断集合中是否存在指定的元素 boolean isEmpty() 判断集合是否为空 int size() 集合的长度,也就是集合中元素的个数
单列迭代器
-
专为集合而存在,用于集合遍历
-
声明方式:Iterator it = c.iterator();
-
方法名 说明 boolean hasNext() 判断集合是否为空/存在 next() 获取循环中的指针
List集合
-
有序集合(也称为序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元
素,并搜索列表中的元素 -
可以重复。且是有序的,有索引
-
方法名 描述 void add(int index,E element) 在此集合中的指定位置插入指定的元素 E remove(int index) 删除指定索引处的元素,返回被删除的元素 E set(int index,E element) 修改指定索引处的元素,返回被修改的元素 E get(int index) 返回指定索引处的元素
-
public static void main(String[] args) { List<String> s = new ArrayList<String>(); s.add("一"); s.add("二"); s.add("三"); for (int i=0;i<s.size();i++){ String param = s.get(i); if(param.equals("一")){ s.add("四"); } } System.out.println(s.toString()); }
列表迭代器
- ListIterator
- 通过List集合的listIterator()方法得到,所以说它是List集合特有的迭代器
- 用于允许程序员沿任一方向遍历的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置
ArrayList集合与LinkedList集合
-
ArrayList集合
底层是数组结构实现,查询快、增删慢 -
LinkedList集合
底层是链表结构实现,查询慢、增删快 -
LinkedList集合的特有功能
-
方法名 说明 public void addFirst(E e) 在该列表开头插入指定的元素 public void addLast(E e) 将指定的元素追加到此列表的末尾 public E getFirst() 返回此列表中的第一个元素 public E getLast() 返回此列表中的最后一个元素 public E removeFirst() 从此列表中删除并返回第一个元素 public E removeLast() 从此列表中删除并返回最后一个元素
Set集合
-
元素存取无序
-
没有索引、只能通过迭代器或增强for循环遍历
-
不能存储重复元素
-
使用:
-
public static void main(String[] args) { //创建集合对象 HashSet<String> hs = new HashSet<String>(); //添加元素 hs.add("hello"); hs.add("world"); hs.add("java"); hs.add("world"); //遍历 for(String s : hs) { System.out.println(s); } }
HashSet集合
- 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,所以是不包含重复元素的集合
LinkedHashSet集合
- 哈希表和链表实现的Set接口,具有可预测的迭代次序
- 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
- 由哈希表保证元素唯一,也就是说没有重复的元素
双列 Map集合
-
特点:键值对映射关系,一个键对应一个值,键不能重复,值可以重复,元素存取无序
-
语法:interface Map<K,V> K:键的类型;V:值的类型
-
方法:
-
方法名 说明 V put(K key,V value) 添加元素 V remove(Object key) 根据键删除键值对元素 void clear() 移除所有的键值对元素 boolean containsKey(Object key) 判断集合是否包含指定的键 boolean containsValue(Object value) 判断集合是否包含指定的值 boolean isEmpty() 判断集合是否为空 int size() 集合的长度,也就是集合中键值对的个数 V get(Object key) 根据键获取值 Set keySet() 获取所有键的集合 Collection values() 获取所有值的集合 Set<Map.Entry<K,V>> entrySet() 获取所有键值对对象的集合
-
案例:
-
public static void main(String[] args) { // 创建一个集合实例 Map<String,String> m = new HashMap<String,String>(); //添加集合 m.put("name","须臾钱"); m.put("sex","男"); m.put("phone","123456"); // 获取所有的值 //因为无序的存在,所有不能用for循环 Collection<String> a = m.values(); for (String s : a) { System.out.println(s); // 循环获取多个集合 } System.out.println("==================="); // 获取集合 if (!m.isEmpty() && m.containsKey("name")){ System.out.println(m.size()); System.out.println(m.get("name")); // 获取单个集合 } }
集合嵌套
ArrayList嵌套HashMap
-
案例
-
public static void main(String[] args) { // 声明arrayList 集合 ArrayList<Map<String,String >> s = new ArrayList<>(); //创建HashMap集合,并添加键值对元素 HashMap<String, String> hm1 = new HashMap<String, String>(); hm1.put("孙策", "大乔"); hm1.put("周瑜", "小乔"); HashMap<String, String> hm2 = new HashMap<String, String>(); hm2.put("郭靖", "黄蓉"); hm2.put("杨过", "小龙女"); //把HashMap作为元素添加到ArrayList集合 s.add(hm1); s.add(hm2); //遍历ArrayList集合 for (Map<String, String> hm : s) { Set<String> keySet = hm.keySet(); for (String key : keySet) { String value = hm.get(key); System.out.println(key + "," + value); } } }
HashMap嵌套ArrayList
-
案例
-
public static void main(String[] args) { //创建map集合 HashMap<String, ArrayList<String>> hm = new HashMap<>(); //创建List集合 ArrayList<String> sgyy = new ArrayList<>(); sgyy.add("赵云"); sgyy.add("张辽"); hm.put("sgyy",sgyy); // 添加arraylist集合到map集合 ArrayList<String> xyj = new ArrayList<>(); xyj.add("女儿国"); xyj.add("师傅"); hm.put("xyj",xyj); // 添加arraylist集合到map集合 // 遍历输出 Set<String> keySet = hm.keySet(); for (String key : keySet) { System.out.println(key); for (String s : hm.get(key)) { System.out.println("\t" + s); } } }
Collections集合工具类
-
方法
-
方法名 说明 public static void sort(List list) 将指定的列表按升序排序 public static void reverse(List<?> list) 反转指定列表中元素的顺序 public static void shuffle(List<?> list) 使用默认的随机源随机排列指定的列表
-
案例
-
//斗地主
泛型
-
它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型
它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数 -
其实就是定义类或者方法的使用形参不加类型,用泛型先代替,之后要用到方法时在传递类型
-
定义格式
-
<类型>:指定一种类型的格式。这里的类型可以看成是形参 <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参 将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
-
优点:1、把运行时期的问题提前到了编译期间 2、避免了强制类型转换
-
//泛型类 修饰符 class 类名<类型> { } //泛型方法 修饰符 <类型> 返回值类型 方法名(类型 变量名) { }
可变参数
-
可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
-
//定义格式 修饰符 返回值类型 方法名(数据类型… 变量名) { } public static int sum(int... a) { int sum = 0; for(int i : a) { sum += i; } return sum; } System.out.println(sum(10, 20));
增强for循环
- 语法格式:
for(元素数据类型 变量名 : 数组/集合对象名) {
循环体;
}
for(Student s : list) { // 对象 集合
System.out.println(s.getName()+","+s.getAge());
}
File类
-
File类介绍
- 它是文件和目录路径名的抽象表示
- 文件和目录是可以通过File封装成对象的
- 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的
-
File类的构造方法
-
方法名 说明 File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的 File实例 File(String parent, String child) 从父路径名字符串和子路径名字符串创建新的 File实例 File(File parent, String child) 从父抽象路径名和子路径名字符串创建新的 File实例 // 其实就是资源句柄
创建 目录或文件
-
方法:
-
方法名 说明 createNewFile() 当具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件 mkdir() 创建由此抽象路径名命名的目录 mkdirs() 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录
判断目录很文件
-
isDirectory() 测试此抽象路径名表示的File是否为目录 isFile() 测试此抽象路径名表示的File是否为文件 exists() 测试此抽象路径名表示的File是否存在
获取 目录和文件
-
getAbsolutePath() 返回此抽象路径名的绝对路径名字符串 getPath() 将此抽象路径名转换为路径名字符串 getName() 返回由此抽象路径名表示的文件或目录的名称 list() 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组 listFiles() 返回此抽象路径名表示的目录中的文件和目录的File对象数组
删除目录或文件
-
方法名 说明 public boolean delete() 删除由此抽象路径名表示的文件或目录
IO流
字节流
- IO流介绍(FileOutputStream)
- IO:输入/输出(Input/Output),流:是一种抽象概念,是对数据传输的总称。也就是说数据在设备间的传输称为流,流的本质是数据传输
- IO流就是用来处理设备间数据传输问题的。常见的应用:文件复制;文件上传;文件下载
- 创建
- FileOutputStream fos = new FileOutputStream(path);
- 创建文件输出流以指定的名称写入文件。如果第二个参数为true ,则字节将写入文件的末尾而不是开头
- IO流的分类
- 字节流
- 字符流
- 使用场景
- 如果操作的是纯文本文件,优先使用字符流
- 如果操作的是图片、视频、音频等二进制文件。优先使用字节流
- 如果不确定文件类型,优先使用字节流。字节流是万能的流
写入
-
方法:
-
write(int b) 将指定的字节写入此文件输出流 一次写一个字节数据 write(byte[] b) 将 b.length字节从指定的字节数组写入此文件输出流 一次写一个字节数组 数据 write(byte[] b, intoff, int len) 将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流 一次写一个字节数组的部分数据
-
案例:
-
public static void main(String[] args) throws IOException { /* 做了三件事情: A:调用系统功能创建了文件,没有则创建 B:创建了字节输出流对象 C:让字节输出流对象指向创建好的文件 */ FileOutputStream fos = new FileOutputStream("E:\\java学习视频\\1-javaSE基础\\day17-File&递归&字节流\\笔记\\test.java"); fos.write(65); fos.close(); } // String的getBytes()方法是得到一个操作系统默认的编码格式的字节数组,可以直接转化成编码格式
读数据
-
FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream ,该文件由文件系统中的路径名name命名
-
步骤:
- 创建字节输入流对象
- 调用字节输入流对象的读数据方法
- 释放资源
-
案例:
-
FileInputStream fis = new FileInputStream("E:\\java学习视频\\1-javaSE基础\\day17-File&递归&字节流\\笔记\\test.java"); int by; /* fis.read():读数据 by=fis.read():把读取到的数据赋值给by by != -1:判断读取到的数据是否是-1 */ while ((by=fis.read())!=-1) { System.out.print((char)by); } //释放资源 fis.close(); //或者 byte[] bys = new byte[1024]; //1024及其整数倍 int len; while ((len=fis.read(bys))!=-1) { System.out.print(new String(bys,0,len)); } //释放资源 fis.close();
复制
-
复制文件内容案例:
-
public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("E:\\java学习视频\\1-javaSE基础\\day17-File&递归&字节流\\笔记\\test.java"); String path2 = "E:\\java学习视频\\1-javaSE基础\\day17-File&递归&字节流\\笔记\\test2.java"; FileOutputStream fos = new FileOutputStream(path2,true); int by; while ((by = fis.read())!=-1){ fos.write(by); } fis.close(); fos.close(); }
字节缓冲流(好像都用这个)
-
lBufferOutputStream:该类实现缓冲输出流。 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统的调用
-
lBufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组。 当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
-
方法:
-
方法名 说明 BufferedOutputStream(OutputStream out) 创建字节缓冲输出流对象 BufferedInputStream(InputStream in) 创建字节缓冲输入流对象
-
案例
-
public static void main(String[] args) throws IOException { //妈蛋 这里是反过来的 FileOutputStream fos = new FileOutputStream("E:\\java学习视频\\1-javaSE基础\\day17-File&递归&字节流\\笔记\\test2.java",true); // 输出流,写入数据 BufferedOutputStream bos = new BufferedOutputStream(fos); bos.write("怕怕怕怕怕怕怕怕怕\r\n".getBytes()); bos.close(); // 输入流,读取数据 FileInputStream fis = new FileInputStream("E:\\java学习视频\\1-javaSE基础\\day17-File&递归&字节流\\笔记\\test2.java"); BufferedInputStream bis = new BufferedInputStream(fis); byte[] b = new byte[1024]; int l; while ((l=bis.read(b)) != -1){ System.out.println(new String(b,0,l)); } }
字符流
-
由于字节流操作中文不是特别的方便,所以Java就提供字符流
-
字符流 = 字节流 + 编码表
-
编码方法:
-
方法名 说明 byte[] getBytes() 使用平台的默认字符集将该 String编码为一系列字节 byte[] getBytes(String charsetName) 使用指定的字符集将该 String编码为一系列字节 String(byte[] bytes) 使用平台的默认字符集解码指定的字节数组来创建字符串 String(byte[] bytes, String charsetName) 通过指定的字符集解码指定的字节数组来创建字符串
-
-
字符流方法
-
方法名 说明 InputStreamReader(InputStream in) 使用默认字符编码创建InputStreamReader对象 InputStreamReader(InputStream in,String chatset) 使用指定的字符编码创建InputStreamReader对象 OutputStreamWriter(OutputStream out) 使用默认字符编码创建OutputStreamWriter对象 OutputStreamWriter(OutputStream out,String charset) 使用指定的字符编码创建OutputStreamWriter对象
-
-
案例
-
public static void main(String[] args) throws IOException { // 字符编码 String s = "我是大帅哥"; byte[] b = s.getBytes("GBK"); System.out.println(Arrays.toString(b)); String ss = new String(b,"GBK"); System.out.println(ss); System.out.println("========================================="); String path2 = "E:\\java学习视频\\1-javaSE基础\\day17-File&递归&字节流\\笔记\\test.java"; //字符流 输出流 OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream(path2,true),"GBK"); osw.write("中国"); osw.close(); System.out.println("========================================="); // 字符流 输入流 InputStreamReader isr = new InputStreamReader(new FileInputStream(path2)); char[] chs = new char[1024]; int len; while ((len = isr.read(chs)) != -1) { System.out.print(new String(chs, 0, len)); } //释放资源 isr.close(); }
字符缓冲流
-
字符缓冲流介绍:
- BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小。默认值足够大,可用于大多数用途
- BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。 默认值足够大,可用于大多数用途
-
方法:
-
方法名 说明 BufferedWriter(Writer out) 创建字符缓冲输出流对象 BufferedReader(Reader in) 创建字符缓冲输入流对象 String readLine() 读一行文字。 结果包含行的内容的字符串不包括任何行终止字符如果流的结尾已经到达,则为null void newLine() 写一行行分隔符,行分隔符字符串由系统属性定义
-
多线程
- 线程和进程理解
- 进程:是正在运行的程序,是系统进行资源分配和调用的独立单位,每一个进程都有它自己的内存空间和系统资源
- 线程:是进程中的单个顺序控制流,是一条执行路径
第一种实现方式
-
继承Thread类
-
方法:
-
void run() 在线程开启后,此方法将被调用执行 void start() 使此线程开始执行,Java虚拟机会调用run方法() void setName(String name) 将此线程的名称更改为等于参数name String getName() 返回此线程的名称 Thread currentThread() 返回对当前正在执行的线程对象的引用
-
-
步骤:
- 定义一个类MyThread继承Thread类
- 在MyThread类中重写run()方法
- 创建MyThread类的对象
- 启动线程
-
案例
package XianChen; public class MyThread extends Thread{ @Override public void run(){ for (int i = 0; i < 100; i++) { System.out.println(getName()+":"+i); } } public MyThread(){ } public MyThread(String name){ super(name); } } package XianChen; public class MyThreadDemo { public static void main(String[] args) { MyThread my1 = new MyThread(); MyThread my2 = new MyThread(); //void setName(String name):将此线程的名称更改为等于参数 name my1.setName("高铁"); my2.setName("飞机"); //Thread(String name) MyThread my3 = new MyThread("高铁"); MyThread my4 = new MyThread("飞机"); my3.setName("高铁"); my4.setName("飞机"); my3.start(); my4.start(); //static Thread currentThread() 返回对当前正在执行的线程对象的引用 System.out.println(Thread.currentThread().getName()); } }
线程优先级
-
分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
-
抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些
-
Java使用的是抢占式调度模型
-
方法:
-
方法名 说明 final int getPriority() 返回此线程的优先级 final void setPriority(intnewPriority) 更改此线程的优先级 线程默认优先级是5;线程优先级的范围是:1-10 static void sleep(longmillis) 使当前正在执行的线程停留(暂停执行)指定的毫秒数 void join() 等待这个线程死亡 void setDaemon(booleanon) 将此线程标记为守护线程,当运行的线程都是守护线程时,Java虚拟机将退出
-
-
生命周期
-
第二种实现方式
-
实现Runnable接口
-
方法:
-
方法名 说明 Thread(Runnable target) 分配一个新的Thread对象 Thread(Runnable target, String name) 分配一个新的Thread对象
-
-
案例:
-
package XianChen; public class Threads implements Runnable{ @Override public void run(){ for(int i=0; i<10; i++) { System.out.println(Thread.currentThread().getName()+":"+i); } } } package XianChen; public class ThredsDemo { public static void main(String[] args) { Threads my = new Threads(); Thread t1 = new Thread(my,"高铁"); Thread t2 = new Thread(my,"飞机"); //启动线程 t1.start(); t2.start(); } }
-
同步代码块解决数据安全问题
-
把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可(线程锁)
-
方法:
-
// 抢票还是超了 synchronized(任意对象) { 多条语句操作共享数据的代码 }
-
-
案例:
-
package XianChen.Demo; public class MaiPiao implements Runnable{ private int tickets = 100; private Object obj = new Object(); @Override public void run() { while (true) { //tickets = 100; //t1,t2,t3 //假设t1抢到了CPU的执行权 //假设t2抢到了CPU的执行权 synchronized (obj) { //t1进来后,就会把这段代码给锁起来 if (tickets > 0) { try { Thread.sleep(100); //t1休息100毫秒 } catch (InterruptedException e) { e.printStackTrace(); } //窗口1正在出售第100张票 System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票"); tickets--; //tickets = 99; } } //t1出来了,这段代码的锁就被释放了 } } } package XianChen.Demo; public class MaiPiaoDemo { public static void main(String[] args) { MaiPiao st = new MaiPiao(); Thread t1 = new Thread(st, "窗口1"); Thread t2 = new Thread(st, "窗口2"); Thread t3 = new Thread(st, "窗口3"); t1.start(); t2.start(); t3.start(); } }
-
同步方法解决数据安全问题
-
同步方法的格式
-
修饰符 synchronized 返回值类型 方法名(方法参数) { 方法体; }
-
-
静态同步方法
-
修饰符 static synchronized 返回值类型 方法名(方法参数) { 方法体; }
-
-
同步方法的锁this、静态同步方法锁class
Lock锁
-
Lock是接口不能直接实例化,这里采用它的实现类ReentrantLock来实例化
-
方法
-
方法名 说明 ReentrantLock() 创建一个ReentrantLock的实例 void lock() 获得锁 void unlock() 释放锁
-
生产者消费者
-
方法
-
方法名 说明 void wait() 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法 void notify() 唤醒正在等待对象监视器的单个线程 void notifyAll() 唤醒正在等待对象监视器的所有线程
-
-
案例需求 生产者消费者案例中包含的类: 奶箱类(Box):定义一个成员变量,表示第x瓶奶,提供存储牛奶和获取牛奶的操作 生产者类(Producer):实现Runnable接口,重写run()方法,调用存储牛奶的操作 消费者类(Customer):实现Runnable接口,重写run()方法,调用获取牛奶的操作 测试类(BoxDemo):里面有main方法,main方法中的代码步骤如下 ①创建奶箱对象,这是共享数据区域 ②创建消费者创建生产者对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用存储牛奶的操作 ③对象,把奶箱对象作为构造方法参数传递,因为在这个类中要调用获取牛奶的操作 ④创建2个线程对象,分别把生产者对象和消费者对象作为构造方法参数传递 ⑤启动线程
网络编程
- 网络编程三要素:IP、端口、协议
端口和协议
-
端口
- 设备上应用程序的唯一标识
-
UDP协议
-
1、用户数据报协议(User Datagram Protocol) 2、UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。 3、由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议通常采用UDP协议,因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,因此在传输重要数据时不建议使用UDP协议
-
-
TCP协议
-
1、传输控制协议 (Transmission Control Protocol) 2、TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,然后再传输数据,它提供了两台计算机之间可靠无差错的数据传输。在TCP连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过“三次握手” 3、三次握手:TCP协议中,在发送数据的准备阶段,客户端与服务器之间的三次交互,以保证连接的可靠 第一次握手,客户端向服务器端发出连接请求,等待服务器确认 第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求 第三次握手,客户端再次向服务器端发送确认信息,确认连接 4、完成三次握手,连接建立后,客户端和服务器就可以开始进行数据传输了。由于这种面向连接的特性,TCP协议可以保证传输数据的安全,所以应用十分广泛。例如上传文件、下载文件、浏览网页等
-
InetAddress类应用
-
方法
-
方法名 说明 static InetAddress getByName(Stringhost) 确定主机名称的IP地址。主机名称可以是机器名称,也可以是IP地址 String getHostName() 获取此IP地址的主机名 String getHostAddress() 返回文本显示中的IP地址字符串
-
UDP通信程序
-
通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接收数据的对象,因此对于基于UDP协议的通信双方而言,没有所谓的客户端和服务器的概念
-
使用DatagramSocket
-
方法:
-
方法名 说明 DatagramSocket() 创建数据报套接字并将其绑定到本机地址上的任何可用端口 DatagramPacket(byte[] buf,int len,InetAddressadd,int port) 创建数据包,发送长度
-
发送
-
使用:DatagramPacket
-
方法:
-
void send(DatagramPacket p) 发送数据报包 void close() 关闭数据报套接字 void receive(DatagramPacket p) 从此套接字接受数据报包
-
-
步骤:
- 创建发送端的Socket对象(DatagramSocket)
- 创建数据,并把数据打包
- 调用DatagramSocket对象的方法发送数据
- 关闭发送端
接收
-
方法:
-
方法名 说明 DatagramPacket(byte[] buf, int len) 创建一个DatagramPacket用于接收长度为len的数据包 byte[] getData() 返回数据缓冲区 int getLength() 返回要发送的数据的长度或接收的数据的长度
-
-
案例
-
package WangLuo; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; public class SendUdpDemo { public static void main(String[] args) throws IOException { /* // 创建实例 DatagramSocket ds = new DatagramSocket(); // 创建数据 //DatagramPacket(byte[] buf, int length, InetAddress address, int port) byte[] bys = "udp,成功了!".getBytes(); DatagramPacket dp = new DatagramPacket(bys,bys.length, InetAddress.getByName("192.168.1.134"),10086); ds.send(dp); ds.close();*/ DatagramSocket ds = new DatagramSocket(); // 字符流获取键盘输入 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String line; while ((line = br.readLine()) != null) { if(line.equals("000")){ break; } byte[] b = line.getBytes(); DatagramPacket dp = new DatagramPacket(b,b.length,InetAddress.getByName("192.168.1.134"),10086); ds.send(dp); } ds.close(); } } package WangLuo; import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; public class ReceiveUdpDemo { public static void main(String[] args) throws IOException { /* DatagramSocket ds = new DatagramSocket(10086); while (true) { //创建一个数据包,用于接收数据 byte[] bys = new byte[1024]; DatagramPacket dp = new DatagramPacket(bys, bys.length); //调用DatagramSocket对象的方法接收数据 ds.receive(dp); //解析数据包,并把数据在控制台显示 System.out.println("数据是:" + new String(dp.getData(), 0, dp.getLength())); }*/ DatagramSocket ds = new DatagramSocket(10086); while (true){ //创建一个数据包,用于接收数据 byte[] bys = new byte[1024]; DatagramPacket dp = new DatagramPacket(bys, bys.length); // 接收数据 ds.receive(dp); //解析数据包,并把数据在控制台显示 System.out.println("数据是:" + new String(dp.getData(), 0, dp.getLength())); } } }
TCP通信程序
- Java为客户端提供了Socket类,为服务器端提供了ServerSocket类
发送
-
方法:
-
方法名 说明 Socket(String host, int port) 创建流套接字并将其连接到指定主机上的指定端口号 InputStream getInputStream() 返回此套接字的输入流 OutputStream getOutputStream() 返回此套接字的输出流
-
接收
-
方法:
-
方法名 说明 ServletSocket(int port) 创建绑定到指定端口的服务器套接字 Socket accept() 监听要连接到此的套接字并接受它 void shutdownInput() 将此套接字的输入流放置在“流的末尾” void shutdownOutput() 禁止用此套接字的输出流
-
-
案例
-
package WangLuo.Tcp; import java.io.*; import java.net.Socket; public class ClientDemo { public static void main(String[] args) throws IOException { Socket s = new Socket("192.168.1.134",10087); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); //封装输出流对象 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); String len; while ((len = br.readLine()) != null){ if (len.equals("886")){ break; } bw.write(len); bw.newLine(); bw.flush(); } s.close(); } } package WangLuo.Tcp; import java.io.BufferedWriter; import java.io.*; import java.net.*; public class ServerDemo { public static void main(String[] args) throws IOException { // 创建绑定到指定端口的服务器套接字 ServerSocket ss = new ServerSocket(10087); // 获取数据包 Socket s = ss.accept(); //获取输入流 BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream())); // 文本 BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\java学习视频\\1-javaSE基础\\day21-网络编程\\笔记\\a.java",true)); String line; while ((line = br.readLine()) != null) { bw.write(line); System.out.println(line); bw.newLine(); bw.flush(); } //释放资源 ss.close(); } }
-
Lambda 表达式
-
其就是函数式编程,实现匿名函数
-
格式化
- (形式参数) -> {代码块}
形式参数:如果有多个参数,参数之间用逗号隔开;如果没有参数,留空即可
->:由英文中画线和大于符号组成,固定写法。代表指向动作
代码块:是我们具体要做的事情,也就是以前我们写的方法体内容
- (形式参数) -> {代码块}
-
组成Lambda表达式的三要素:
- 形式参数,箭头,代码块
-
案例
-
// 普通方式 new Thread(()->{ System.out.println("1111111"); }).start();
-
注意事项
- 使用Lambda必须要有接口,并且要求接口中有且仅有一个抽象方法
- 必须有上下文环境,才能推导出Lambda对应的接口
- 根据局部变量的赋值得知Lambda对应的接口
Runnable r = () -> System.out.println(“Lambda表达式”); - 根据调用方法的参数得知Lambda对应的接口
- new Thread(() -> System.out.println(“Lambda表达式”)).start();
- 根据局部变量的赋值得知Lambda对应的接口
函数式接口
-
有且仅有一个抽象方法的接口
-
如何检测一个接口是不是函数式接口
- @FunctionalInterface
放在接口定义的上方:如果接口是函数式接口,编译通过;如果不是,编译失败
- @FunctionalInterface
-
注意事项
- 我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我不写这个注解,只要保证满足函数
式接口定义的条件,也照样是函数式接口。但是,建议加上该注解
- 我们自己定义函数式接口的时候,@FunctionalInterface是可选的,就算我不写这个注解,只要保证满足函数
-
案例
-
public class RunnableDemo { public static void main(String[] args) { //在主方法中调用startThread方法 //匿名内部类的方式 startThread(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + "线程启动了"); } }); //Lambda方式 startThread(() -> System.out.println(Thread.currentThread().getName() + "线 程启动了")); } private static void startThread(Runnable r) { new Thread(r).start(); } }
-
类的加载器与反射模块
类的加载器
-
负责将.class文件加载到内存中,并为之生成对应的 java.lang.Class 对象。虽然我们不用过分关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行!
-
Java中的内置类加载器
- Bootstrap class loader:它是虚拟机的内置类加载器,通常表示为null ,且没有父null
- Platform class loader:平台类加载器可以看到所有平台类 ,平台类包括由平台类加载器或其祖先定义的JavaSE平台API,其实现类和JDK特定的运行时类
- System class loader:它也被称为应用程序类加载器 ,与平台类加载器不同。 系统类加载器通常用于定义应用程序类路径,模块路径和JDK特定工具上的类
- 类加载器的继承关系:System的父加载器为Platform,而Platform的父加载器为Bootstrap
-
ClassLoader 中的两个方法
-
static ClassLoader getSystemClassLoader() 返回用于委派的系统类加载器 ClassLoader getParent() 返回父类加载器进行委派
-
反射
概述:
是指在运行时去获取一个类的变量和方法信息。然后通过获取到的信息来创建对象,调用方法的一种机制。
由于这种动态性,可以极大的增强程序的灵活性,程序不用在编译期就完成确定,在运行期仍然可以扩展
通俗话来说:我们能通过这个对象看到类的结构,这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象称之为:反射
- Java代码在计算机中经历的三个阶
- 源代码阶段(在磁盘)、Class类对象阶段(在内存)、Runtime运行时阶段(在内存)
- 构造方法
- 构造方法对象:Constructor[] cons
- 成员变量对象:Field[] fields
- 成员方法对象:Method[] methods
获取Class对象的三种方式
-
Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象(源码阶段)
-
类名.class:通过类名的属性class获取(Class类对象阶段)
-
对象.getClass():getClass()方法在Object类中定义着(有对象阶段)。
反射获取类的内容
-
获取成员变量
-
Field[] getFields() :获取所有public修饰的成员变量 Field getField(String name) 获取指定名称的 public修饰的成员变量 Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符 Field getDeclaredField(String name)
-
-
获取构造方法
-
Constructor<?>[] getConstructors()返回所有公共构造方法对象的数 组 Constructor<?>[] getDeclaredConstructors() 返回所有构造方法对象的数组 Constructor getConstructor(Class<?>... parameterTypes) 返回单个公共构造方法对象 Constructor getDeclaredConstructor(Class<?>... parameterTypes)返回单个构造方法对象 T newInstance([Object...initargs]) 根据指定的构造方法创建对象
-
-
获取成员方法
-
Method[] getMethods() 返回所有公共成员方法对象的数组,包 括继承的 Method[] getDeclaredMethods() 返回所有成员方法对象的数组,不包括 继承的 Method getMethod(String name, Class<?>... parameterTypes) 返回单个公共成员方法对象 Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回单个成员方法对象 Objectinvoke(Object obj,Object... args) 调用obj对象的成员方法,参数是args,返回值是Object类型
-
-
获取类名
-
String getName()
-
-
案例:
-
package ClassLoaders; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; public class ReflectDemo { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException { // 导入类路径 //Class c = Class.forName(""); // 类名 Class<ClassLoaderDemo> c2 = ClassLoaderDemo.class; // 对象 ClassLoaderDemo cld = new ClassLoaderDemo(); Class c3 = cld.getClass(); //System.out.println(c); System.out.println(c2); System.out.println(c3); System.out.println(c3.getName()); System.out.println("====================================================="); /* 反射获取构造方法并使用 */ Class<Student> cla = Student.class; Constructor<?>[] cons = cla.getDeclaredConstructors(); for (Constructor a : cons) { System.out.println(a); } System.out.println("========================"); Constructor<Student> consC = cla.getConstructor(String.class, int.class, String.class); Object obj = consC.newInstance("林青霞", 30, "西安"); System.out.println(obj); /* 获取成员变量 */ System.out.println("========================"); Field[] fields = cla.getDeclaredFields(); for (Field a : fields) { System.out.println(a); } System.out.println("========================"); // 重新赋值 Object fieldObj = cla.newInstance(); Field nameField = cla.getDeclaredField("name"); nameField.setAccessible(true); nameField.set(fieldObj, "林青霞"); System.out.println(fieldObj); System.out.println("========================"); /* 成员方法 */ Method[] methods = cla.getDeclaredMethods(); for (Method a : methods) { System.out.println(a); } System.out.println("=========================="); Object obj1 = cla.newInstance(); Method m3 = cla.getMethod("method3", String.class, int.class); Object o = m3.invoke(obj1, "林青霞", 30); System.out.println(o); } }
-