2.抽象类中存在构造方法;
3.抽象类的子类:
1) 必须要重写父类中所有的抽象方法;
2) 可以将自己也变成一个抽象类;
4.抽象类中可以没有抽象方法,但是有抽象方法的类一定是抽象类
1.构造代码块:每次构造方法执行时,都会执行该代码块中的代码,并且在构造方法执行前执行
作用:将多个构造方法中相同的代码,抽取到构造代码块中
2.静态代码块:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
作用:在类加载的时候做一些数据初始化的操作
3.局部代码块:限定变量的生命周期,及早释放,提高内存利用率
1.加载main方法所在的类,先执行静态代码块
2.加载main方法中的内容,例如对子类的实例化之后:加载父类,找父类中的静态代码块,然后找子类的静态代码块,然后执行父类的构造方法,如果父类有构造代码块,就先执行构造代码块,再执行无参构造方法,最后执行子类的无参构造方法,同理有构造代码块,先执行构造代码块,结束;
1.当实现多个接口时,接口中有同一个方法,该方法在实现类中并不冲突且只重写一次。
2.接口中的变量都是final修饰是常量,默认加上:pubclic static final
3.接口中的方法的权限修饰符public 、abstract可省略;
JDK8版本后 允许在接口中定义非抽象方法,但是需要使用关键字default修饰,这些方法就是默认方法 作用:解决接口升级的问题 接口中默认方法的定义格式︰ 格式: public default返回值类型方法名(参数列表){} 范例: public default void show) { } 接口中默认方法的注意事项∶ 默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候去掉default关键字public可以省略,default不能省略 补充:当实现两个接口中共有的default修饰的方法时,实现类必须重写该方法;
接口中静态方法的定义格式︰ 格式: public static返回值类型方法名(参数列表){} 范例: public static void show){ } 接口中静态方法的注意事项︰ 静态方法只能通过接口名调用,不能通过实现类名或者对象名调用 public可以省略,static不能省略
增加了private修改的方法,作用是为了将接口中重复的代码提取出来新建一个方法而又不希望这个方法被其他类访问
如果发现一个类中所有的方法都是抽象方法,那么就可以将该类,改进为一个接口 涉及到了接口大面积更新方法,而不想去修改每一个实现类,就可以将更新的方法,定义为带有方法体的默认方法希望默认方法调用的更加简洁,可以考虑设计为static静态方法。(需要去掉default关键字) 默认方法中出现了重复的代码,可以考虑抽取出一个私有方法。(需要去掉default关键字)
类和类的关系 继承关系,只能单继承,但是可以多层继承 类和接口的关系 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口 接口和接口的关系 继承关系,可以单继承,也可以多继承
构造方法: 同继承一样,子类会通过super访问父类构造方法
成员变量:编译看左边(父类) , 执行看左边(父类)
成员方法:编译看左边(父类) , 执行看右边(子类)
多态的好处 :提高了程序的扩展性
具体体现:定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的任意子对象
多态的弊端:不能使用子类的特有功能
向上转型
从子到父,父类引用指向子类对象
向下转型
从父到子,父类引用转为子类对象:Fu fu = new Zi(); Zi zi = (Zi) fu;
内部类:就是在一个类中定义一 个类。 举例:在一个A类的内部定义一 -个B类 , B类就被称为内部类
内部类的访问特点
内部类可以直接访问外部类的成员,包括私有,外部类要访问内部类的成员,必须创建对象
按照内部类在类中定义的位置不同,可以分为如下两种形式
在类的成员位置 :成员内部类
成员内部类,也属于(成员) ,既然是成员就可以被一些修饰符所修饰
●private 私有成员内部类访问:在自己所在的外部类中创建对象访问。
●static 静态成员内部类访问格式:外部类名.内部类名对象名= new外部类名.内部类名();
静态成员内部类中的静态方法:外部类名.内部类名.方法名0;
局部内部类是在方法中定义的类,所以外界是无法直接使用,需要在方法内部创建对象并使用
该类可以直接访问外部类的成员,也可以问方法内的局部变量;
概述:匿名内部类本质上是一个特殊的局部内部类 (定义在方法内部)
前提:要存在一个接口或类
Lambda表达式的使用前提
1.有一个接口
2.接口中有且仅有一个抽象方法
3.可以有参和无参,允许有返回值和无返回值
具体格式:方法名((参数列表)->{重新接口的一个方法体});
Lambda表达式的省略模式
省略规则:
●参数类型可以省略 ,但是有多个参数的情况下,不能只省略一个
●如果参数有且仅有一 一个,那么小括号可以省略
●如果代码块的语句只有一条,可以省略大括号和分号,甚至是returm
1.所需类型不同
●匿名内部类 :可以是接口,也可以是抽象类,还可以是具体类
●Lambda表达式 :只能是接口
2.使用限制不同
●如果接口中有且仅有一个抽象方法,可以使用L ambda表达式,也可以使用匿名内部类
●如果接口中多于-个抽象方法,只能使用匿名内部类,而不能使用L ambda表达式
3.实现原理不同
●匿名内部类:编译之后,产生一个单独的.class字节码文件☆☆☆☆☆
●Lambda表达式:编译之后,没有一个单独的.class字节码文件。对应的字节码会在运行的时候动态生成
1 , Object类是所有类的直接或者间接父类
2 ,直接打印一个对象就是打印这个对象的toString方法的返回值
3 , Object类的toString方法得到的是对象的地址值
4 , 我们一般会对toString方法进行重写
1.探究源码发现equals本质上是比较的地址值,我们往往将对象用equals来进行比较,就会发现对象的地址值不相等,从而无法达到比较内容,因此我们必须要重写equals方法才能达到我们比较内容的目的,之前的String类型比较内容是因为string是基本类型,创建的变量内容都是在堆内存中只有一份
●装箱: 把基本数据类型转换为对应的包装类类型
●拆箱:把包装类类型转换为对应的基本数据类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BxKMFlT2-1631271826425)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210812183158236.png)]
●如果有n个数据进行排序,总共需要比较n-1次
●每一次比较完毕 ,下一次的比较就会少-个数据参与
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gX6Dc7XB-1631271826427)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210813181642621.png)]
1 . 北京时间需要在世界标准时间上加8小时。
2. 1秒= 1000毫秒
3 . 计算机中的时间原点为: 1970年1月1日00:00:00
public static void main(String[] args) { //当前时间 Date date1 = new Date() ; System.out.println(date1) ; //时间原点 Date date2 = new Date(0); System.out.println(date2) ; //原点加一个小时 Date date3 = new Date (3600*1000); System . out. println(date3); //因为我们国家是在东八区,所以原点是早上八点,加一个小时就是早上九点 //格式化 Date date5 = new Date(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日 HH:mm :ss "); System.out.println(sdf.format(date5)); //解析 String s = "2021 年 08 月 15 日 17:55 :21 "; SimpleDateFormat sdf = new SimpleDateFormat("yyyy 年 MM 月 dd 日 HH:mm :ss "); System.out.println(sdf.parse(s));
1.空参构造:把当前时间封装成一个date对象;
2.有参构造:把从时间原点开始,过了指定毫秒的时间,封装成一个Date对象需要考虑时差问题;
…服了没保存
//LocalDateTime使用方法 LocalDateTime ldt = LocalDateTime.now(); System.out.println(ldt); LocalDateTime of = LocalDateTime.of(2020, 8, 15, 11, 11, 11); System.out.println(of); //获取年 int year = of.getYear(); System.out.println(year); //获取月 System.out.println(of.getMonthValue()); //获取月份中的第几天 System.out.println(of.getDayOfMonth()); //获取一年中的第几天 System.out.println("这是一年中的第"+of.getDayOfYear()); //获取分钟 System.out.println(of.getMinute()); //获取小时 System.out.println(of.getHour()); //格式化 DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss"); System.out.println(of.format(dateTimeFormatter)); LocalDateTime of = LocalDateTime.of(2020, 8, 15, 11, 11, 11); //解析 String s = "2020年08月15日 11:11:11"; DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy年MM System.out.println(LocalDateTime.parse(s, dateTimeFormatter)); //plus系列方法 System.out.println(LocalDateTime.of(2020, 8, 15, 11, 11, 11).plusYears(1)) System.out.println(LocalDateTime.of(2020, 8, 15, 11, 11, 11).plusMonths(2) System.out.println(LocalDateTime.of(2020, 8, 15, 11, 11, 11).plusDays(2)); System.out.println(LocalDateTime.of(2020, 8, 15, 11, 11, 11).plusHours(1)) System.out.println(LocalDateTime.of(2020, 8, 15, 11, 11, 11).plusMinutes(1 System.out.println(LocalDateTime.of(2020, 8, 15, 11, 11, 11).plusSeconds(1 System.out.println(LocalDateTime.of(2020, 8, 15, 11, 11, 11).withYear(1969 LocalDate localDate1 = LocalDate.of(2020, 3, 5); LocalDate localDate2 = LocalDate.of(2035, 8, 25); //period类 Period period = Period.between(localDate1, localDate2); System.out.println(period.getYears()); System.out.println(period.getMonths()); System.out.println(period.getDays()); System.out.println(period.toTotalMonths()); //duration类 LocalDateTime localDateTime1 = LocalDateTime.of(2020,1,1,15,26,58); LocalDateTime localDateTime2 = LocalDateTime.of(2020,1,2,19,59,26); Duration duration = Duration.between(localDateTime1,localDateTime2); System.out.println(duration); 获得此时间间隔的秒 System.out.println(duration.toSeconds()); 获得此时间间隔的毫秒 System.out.println(duration.toMillis()); 获得此时间间隔的纳秒 System.out.println(duration.toNanos()); duration.toHours();
1.数组的长度是不可变的,集合的长度是可变的。
2.数组可以存基本数据类型和引用数据类型。集合只能存引用数据类型,如果要存基本数据类型,需要存对应的包装类。
1.集合分为单列和双列
2.单列的父接口为Collection,继承他的子接口有List、Set,其中,List接口允许重复值存在,Set接口中没有重复值
3.双列的接口为Map,其实现类有HashMap、TreeMap;
1.removeIf方法:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CiubQZgA-1631271826429)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210819015511122.png)]
//将集合中的内容清空 collection.clear(); //判断集合是否存在指定元素aaa collection.contains("aaa"); //判断集合是否为空 collection.isEmpty();
Collection<String> list = new ArrayList<>(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); list.add("e"); //获取迭代器对象 Iterator<String> it = list.iterator(); //当前位置是否有元素可以被取出 System.out.println(it.hasNext()); //取出当前位置的元素,并将迭代器往后移动一个索引的位置 System.out.println(it.next()); System.out.println(it.next()); //打印 true a b //优化 while(it.hasNext()){ System.out.println(it.next()); } //remove方法 while(it.hasNext()){ String s = it.next(); if ("b".equals(s)) { it.remove(); } }
使用条件:单列集合Collection继承了Iterable,所以只有继承了Iterable的类才可以有for增强和迭代器的使用,而双列集合则不能使用for增强和迭代器
ArrayList<String> list1 = new ArrayList<>(); list1.add("a"); list1.add("b"); list1.add("b"); list1.add("c"); list1.add("d"); list1.add("e"); for (String str:list1){ System.out.println(str); }
for增强:
1,数据类型一定是集合或者数组中元素的类型
2 , str仅仅是一个变量名而已,在循环的过程中,依次表示集合或者数组中的每一个元素3, list就是要遍历的集合或者数组
List<String > list1 = new ArrayList<>(); list1.add("aaa"); list1.add("bbb"); list1.add("ccc"); list1.add("ddd"); //List特有的add方法类型,void list1.add(1,"插入到1索引处"); Iterator<String> it = list1.iterator(); while (it.hasNext()){ String s = it.next(); System.out.println(s); } System.out.println("------------"); //List特有的remove方法类型,返回被删除的元素 String remove = list1.remove(1); System.out.println("被删除的元素为:"+remove); for (String s : list1) { System.out.println(s); } //List特有的set方法类型:返回被修改的元素 System.out.println("------------"); String abc = list1.set(1, "abc"); for (String s : list1) { System.out.println(s); } //List特有的get方法类型 System.out.println("------------"); String s = list1.get(2); System.out.println("获取的元素为:"+s);
LinkedList<String> link = new LinkedList<>(); link.add("aaa"); link.add("bbb"); link.add("ccc"); link.add("ddd"); //在列表开头插入指定的元素void link.addFirst("添加第一个"); //在列表末尾插入指定的元素void link.addLast("添加最后一个"); //获取第一个元素,返回第一个元素 System.out.println(link.getFirst()); //获取最后一个元素,返回最后一个元素 System.out.println(link.getLast()); //删除第一个并返回第一个元素 System.out.println(link.removeFirst()); //删除最后一个并返回最后一个元素 System.out.println(link.removeLast());
1.TreeSet集合特点
不包含重复元素的集合
没有带索引的方法
可以将元素按照规则进行排序
2.自然排序
@Override public int compareTo(Student o) { // //按照年龄进行排序 // int result = this.age - o.age; // return result; //按照年龄名字进行排序 int result = this.age - o.age; result = result == 0 ? this.name.compareTo(o.getName()) : result; return result; }
3.比较器排序
TreeSet<Student> is = new TreeSet<>(new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { //o1表示要存入的元素 //o2表示已经存在的元素 int result = o1.getAge() - o2.getAge(); result = result == 0 ? o1.getName().compareTo(o2.getName()) : result; return result; } });
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0RKy4Xvs-1631271826431)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210823160854854.png)]
红黑树小结
红黑树不是高度平衡的,它的平衡是通过"红黑规则"进行实现的规则如下:
1.每一个节点或是红色的,或者是黑色的。2.根节点必须是黑色
3.如果一个节点没有子节点或者父节点,则该节点相应的指针十属性值为Nil,这些Nil视为叶节点,每个叶节点(Nil)是黑色的;4.不能出现两个红色节点相连的情况
5.对每一个节点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点;
1.HashSet集合特点
底层数据结构是哈希表
不能保证存储和取出的顺序完全一致
没有带索引的方法,所以不能使用普通for循环遍历·
由于是Set集合,所以元素唯一
2.哈希值
哈希值(哈希码值)∶是JDK根据对象的地址或者属性值,算出来的int类型的整数
Object类中有一个方法可以获取对象的哈希值
public int hashCode():根据对象的地址值计算出来的哈希值
对象的哈希值特点
如果没有重写hashCode方法,那么是根据对象的地址值计算出的哈希值。
同一个对象多次调用hashCode()方法返回的哈希值是相同的不同对象的哈希值是不一样的。
如果重写了hashCode方法,一般都是通过对象的属性值计算出哈希值。
如果不同的对象属性值是一样的,那么计算出来的哈希值也是样的。
3.哈希表
JDK8之前,底层采用数组+链表实现。默认长度16,默认加载因子0.75,
首先会先获取元素的哈希值,计算出在数组中应存入的索引判断该索引处是否为null,如果是null,直接添加,如果不是null,则与链表中所有的元素,通过equals方法比较属性值只要有一个相同,就不存,如果都不一样,才会存入集合。老元素挂在新元素下面。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ilRnjL14-1631271826432)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210825023001392.png)]
lnterface Map<K,V>K∶键的数据类型;V:
值的数据类型键不能重复,值可以重复
键和值是——对应的,每一个键只能找到自己对应的值
(键+值)这个整体我们称之为“键值对”或者“键值对对象”,在Java中叫做“Entry对象”。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VpKFJbfh-1631271826434)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210825141553068.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zLlI7S0n-1631271826435)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210825145310247.png)]
map集合的遍历第一种:
Map<Integer , Integer> map = new HashMap<>(); map.put(1,2); map.put(3,4); map.put(5,6); map.put(7,8); Set<Integer> integers = map.keySet(); for (Integer integer : integers) { int value = map.get(integer); System.out.println(integer+"---"+value); }
map集合的遍历第二种:
Map<Integer , Integer> map = new HashMap<>(); map.put(1,2); map.put(3,4); map.put(5,6); map.put(7,8); Set<Map.Entry<Integer, Integer>> entries = map.entrySet(); for (Map.Entry<Integer, Integer> entry : entries) { System.out.println(entry.getKey()+"--------"+entry.getValue()); }
TreeMap底层是红黑树结构的
依赖自然排序或者比较器排序,对建进行排序
·如果键存储的是自定义对象,需要实现Comparable接口或者在创建TreeMap对象时候给出比较器排序规则
可变参数∶就是形参的个数是可以变化的
格式∶修饰符返回值类型方法名(数据类型…变量名){}范例: public static int sum(int… a){ }
可变参数注意事项
这里的变量其实是一个数组
如果一个方法有多个参数,包含可变参数,可变参数要放在最后
/** * 获取流的方法 * 单列集合;集合对象.stream(); * 双列结合:不能直接获取,需要间接获取 * 集合对象.keySet().stream(); * 集合对象.entrySet().stream(); * 数组:Arrays.stream(数组名) * 同种数据类型的多个数据:Stream.of(数据1,数据2,数据3,,,,); */ public class demo01 { public static void main(String[] args) { //单列集合 ArrayList<String> alist = new ArrayList<>(); alist.add("fd"); alist.add("fd"); alist.add("tr"); alist.add("tr"); alist.stream().forEach(s-> System.out.println(s)); //双列集合 HashMap<String,Integer> hm = new HashMap<>(); hm.put("zhangsan",23); hm.put("lisi",24); hm.put("wangwu",25); hm.put("zhaoliu",26); //获取方法1 //获取所有的键 //再把这个Set集合中所有的键放到Stream流中 hm.keySet().stream().forEach(s -> System.out.println(s)); //获取方法2 hm.entrySet().stream().forEach(s-> System.out.println(s)); //数组 int[] arr = {1,2,3,45,6}; Arrays.stream(arr).forEach(s-> System.out.println(s)); //同种数据类型的多个数据 Stream.of(1,2,3,4,5,6,7,8,9,1,0).forEach(s-> System.out.println(s)); } }
/** * 过滤器 */ public class demo02 { public static void main(String[] args) { ArrayList<String> alist = new ArrayList<>(); alist.add("小明"); alist.add("小张"); alist.add("小红"); alist.add("小李"); alist.add("大明"); alist.add("二明"); alist.add("大哥"); //匿名内部类实现 alist.stream().filter(new Predicate<String>() { @Override public boolean test(String s) { boolean result = s.startsWith("小"); return result; } }).forEach(s-> System.out.println(s)); //lambda表达式实现 alist.stream().filter((String s)-> { boolean result = s.startsWith("小"); return result; }).forEach(s-> System.out.println(s)); //lambda表达式的省略 alist.stream().filter(s -> s.startsWith("大")).forEach(s-> System.out.println(s)); } }
/** * Stream流的中间方法 */ public class demo03 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("小明"); list.add("小张"); list.add("小红"); list.add("小李"); list.add("大明"); list.add("二明"); list.add("大哥"); list.add("大哥"); //limit方法:截取指定参数个数的数据 list.stream().limit(2).forEach(s-> System.out.println(s)); System.out.println("-------------"); //skip方法:跳过指定参数个数的数据 list.stream().skip(2).forEach(s-> System.out.println(s)); System.out.println("-------------"); //concat方法:合并两个流为一个流 ArrayList<String> list1 = new ArrayList<>(); list1.add("a"); list1.add("b"); list1.add("v"); list1.add("d"); Stream.concat(list.stream(),list1.stream()).forEach(s-> System.out.println(s)); //distinct方法:去除流中重复的元素,依赖hashcode和equals方法 list.stream().distinct().forEach(s-> System.out.println(s)); } }
ArrayList<String> list = new ArrayList<>(); list.add("小明"); list.add("小张"); list.add("小红"); list.add("小李"); list.add("大明"); list.add("二明"); list.add("大哥"); list.add("大哥"); //终结方法遍历流中的数据 list.stream().forEach(s-> System.out.println(s)); //统计流中的个数 System.out.println(list.stream().count());
/** * 添加10个元素到集合,输出偶数并保存到新集合中 * */ public class demo06 { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<>(); for (int i = 1; i < 11; i++) { list.add(i); } list.add(10); list.add(10); list.add(10); //collect:负责收集数据 //Collectors.toList():在底层会创建一个List集合,并把所有的数据添加到集合中 System.out.println(list.stream().filter(number -> number % 2 == 0).collect(Collectors.toList())); System.out.println(list.stream().filter(number -> number % 2 == 0).collect(Collectors.toSet())); System.out.println("----------"); //toMap ArrayList<String> list1 = new ArrayList<>(); list1.add("zhangsan,23"); list1.add("lisi,24"); list1.add( "wangwu,25"); Map<String, Integer> collect = list1.stream().filter(s -> Integer.parseInt(s.split(",")[1]) >= 24).collect(Collectors.toMap( s -> s.split(",")[0], s -> Integer.parseInt(s.split(",")[1]) )); System.out.println(collect); } }
File file = new File("E:\\file\\aa.java"); boolean newFile = file.createNewFile(); System.out.println(newFile); File file1 = new File("E:\\file\\asa\\bbb\\ccc"); System.out.println(file1.mkdirs());
1.不走回收站的.
2.如果删除的是文件,那么直接删除.如果删除的是文件夹,那么能删除空文件夹
3.如果要删除一个有内容的文件夹,只能先进入到这个文件夹,把里面的内容全部删除完毕,才能再次删除这个文件
4.总结来说,只能删除文件和空文件夹
listFiles方法注意事项∶
当调用者不存在时,返回null当调用者是一个文件时,返回null;
当调用者是一个空文件夹时,返回一个长度为0的数组;
当调用者是一个有内容的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回;
当调用者是一个有隐藏文件的文件夹时,将里面所有文件和文件夹的路径放在File数组中返回,包含隐藏内谷当调用者是一个需要权限才能进入的文件夹时,返回null;
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XjUDCm01-1631271826441)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210828191437394.png)]
字节流写数据实现换行
写完数据后,加换行符
windows:\r\n、linux:\n、mac:\r
“\r”.getbyte()
构造方法FileOutputStream(String name,boolean append)里面的第二个参数设置为true,即可完成对指定文件的续写不会清空文集爱你原有的内容;
FileOutputStream fos = new FileOutputStream("homework\\aaa\\a.txt",true); //2.写数据 fos.write(97); //3.释放资源 fos.close();
FileInputStream fis = new FileInputStream("homework\\aaa\\a.txt"); int b ; while ((b = fis.read())!=-1){ System.out.print((char)b); }
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\黑马\\课余视频资料以及面试\\sxt马士兵_设计模式\\sxt马士兵_设计模式\\尚学堂科技_马士兵_设计模式_01_Observer\\01_Observer_视频\\01_提出问题_1.avi")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("C:\\Users\\admin\\Desktop\\01_提出问题_1.avi")); int b; while ((b = bis.read())!=-1){ bos.write(b); } bis.close(); bos.close();
注:下图为汉字储存和展示过程解析
String s = "我爱学习a1"; //idea默认按照utf-8进行编码,一个汉字占三个字节,一个字节占一个字节 byte[] bytes = s.getBytes(); System.out.println(Arrays.toString(bytes)); //按照指定编码格式gbk进行编码 byte[] bytes1 = s.getBytes("gbk"); System.out.println(Arrays.toString(bytes1)); byte[] bytes2 = {-26, -120, -111, -25, -120, -79, -27, -83, -90, -28, -71, -96, 97, 49}; byte[] bytes3 = {-50, -46, -80, -82, -47, -89, -49, -80, 97, 49}; //按照idea默认utf-8进行解码 String s1 = new String(bytes2); //按照指定编码格式gbk进行解码 String s2 = new String(bytes3,"gbk"); System.out.println(s1); System.out.println(s2);
小结:
1,想要进行拷贝,一律使用字节流或者字节缓冲流。
2,想要把文本文件中的数据读到内存中,请使用字符输入流。
想要把内存中的数据写到文本文件中,请使用字符输出流。
3,GBK码表一个中文两个字节,UTF-8编码格式一个中文3个字节。
FileWriter fw = new FileWriter("homework\\aaa\\a.txt",true); fw.write(98); fw.write("\n"); char[] chars = {97,98,99,100,101,102}; fw.write(chars); fw.write("\n"); fw.write(chars,0,3); fw.write("黑马"); fw.close();
flush()方法可以刷新文件,刷新后文件的内容即可显示;
FileReader fr = new FileReader("homework\\aaa\\a.txt"); char[] chars = new char[1024]; int b; while ((b = fr.read(chars))!=-1){ System.out.print(new String(chars,0,b)); } fr.close();
BufferedReader br = new BufferedReader(new FileReader("homework\\aaa\\b.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("homework\\aaa\\b.txt",true)); char[] chars = new char[1024]; int len; while((len = br.read(chars))!=-1){ System.out.println(new String(chars,0,len)); } br.close(); bw.write(97); bw.close(); //特有的换行代码,根据操作系统的不同,底层调用不同的换行代码 bw.newLine(); //读一行,如果读不到数据则返回null String line = br.readLine();
1.如果想要这个类的对象能被序列化,那么这个类必须要实现一个接口serializable
serializable接口称之为是一个标记性接口,里面没有任何的抽象方法
只要一个类实现了这个serializable接口,那么就表示这个类的对象可以被序列化.
public static void main(String[] args) throws IOException { User user = new User("张三","sdjffs"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("a.txt")); oos.writeObject(user); oos.close(); } //实现Serializable接口 public class User implements Serializable {...} //解决序列号不一致问题 private static final long serialversionUID = 25l; //加入关键字transient将使得该属性不被序列化 private transient String password;
Properties概述∶
是一个Map体系的集合类
Properties中有跟IO相关的方法
只存字符串
不允许存在同一个键
特有方法: //设置键值对 Properties pps = new Properties(); pps.setProperty("河南","郑州"); pps.setProperty("四川","成都"); pps.setProperty("湖北","武汉"); System.out.println(pps); //根据键获取值 String 河南 = pps.getProperty("河南"); //从该属性列表中返回一个不可修改的键集,几种键及其对应的值是字符串 Set<String> strings = pps.stringPropertyNames(); for (String string : strings) { String property = pps.getProperty(string); System.out.println(property); }
遍历:和map集合遍历相同
//加载properties文件 public static void main(String[] args) throws IOException { Properties prop = new Properties(); FileReader fr = new FileReader("a.properties"); prop.load(fr); fr.close(); System.out.println(prop); } //写入properties文件 public static void main(String[] args) throws IOException { Properties prop = new Properties(); prop.put("user","lisi"); prop.put("password","123456"); FileWriter fw = new FileWriter("b.properties"); //两个参数,第一个为字符流,第二个为注释 prop.store(fw,"this is a comments"); }
public class MyThread extends Thread{ @Override public void run() { //多线程代码 for (int i = 0; i < 100; i++) { System.out.println("线程被执行了"+i); } } } //测试 public class MyThreadTest { public static void main(String[] args) { MyThread myThread1 = new MyThread(); MyThread myThread2 = new MyThread(); myThread1.start(); myThread2.start(); } }
两个小问题:
1.为什么要重写run()方法?
因为run()是用来封装被线程执行的代码
2.run()方法和start()方法的区别?
run():封装线程执行的代码,直接调用,相当于普通方法的调用,并没有开启线程。start():启动线程﹔然后由JVM调用此线程的run()方法
public class MyRunnableTest { public static void main(String[] args) { Thread thread1 = new Thread(()->{ for (int i = 0; i < 100; i++) { System.out.println("runnable1 "+i); } }); Thread thread2 = new Thread(()->{ for (int i = 0; i < 100; i++) { System.out.println("runnable2 "+i); } }); thread1.start(); thread2.start(); } }
多线程的实现方式方式3∶Callable和Future
1.定义一个类MyCallable实现Callable接口
2.在MyCallable类中重写call()方法
3.创建MyCallable类的对象
4.创建Future的实现类FutureTask对象,把MyCallable对象作为构造方法的参数
5.创建Thread类的对象,把FutureTask对象作为构造方法的参数
6.启动线程
7.再调用get方法,就可以获取线程结束之后的结果,get方法本质是获取线程结束之后的返回值,所以get代码要写在线程启动之后
public static void main(String[] args) { Thread th = new Thread(new FutureTask<>(()->{ for (int i = 0; i < 100; i++) { System.out.println("运行1第"+i+"次"); } return "运行完了"; })); th.start(); Thread th1 = new Thread(new FutureTask<>(()->{ for (int i = 0; i < 100; i++) { System.out.println("运行2第"+i+"次"); } return "运行完了"; })); th1.start(); }
1.实现了Thread类:可使用里面的getName()方法、setName方法:为线程设置名字。有参构造也可设置名字,但继承类要重载构造方法;
2.public static Thread currentThread():返回对当前正在执行的线程对象的引用,在实现接口过程中,用Thread.currentThread()获得当前线程的名字;
3.public static void sleep(long time):让线程休眠指定的时间,单位为毫秒。
public class MyThread extends Thread{ @Override public void run() { //多线程代码 for (int i = 0; i < 100; i++) { try { //休眠指定时间 Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName()+"@@"+i); } } }
线程有两种调度模型
1.分时调度模型︰所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
2.抢占式调度模型︰优先让优先级高的线程使用CPU,如果线程的优先级相同传那么会随机选择一个,优先级高的线程获取的CPU时间片相对多一些
Java使用的是抢占式调度模型
//设置线程的优先级,范围:1-10 public final void setPriority(int newPriority) //获取线程的优先级,默认为5 public final int getPriority() //当普通线程执行完成之后,守护线程也会停止,不过不是立刻停下来 thread.setDaemon(true);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qy5lcfgL-1631271826448)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210901185257823.png)]
@Override public void run() { while (true) { synchronized (oj) { if (ticket <= 0) { break; } else { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } ticket--; System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩下" + ticket + "张"); } } } }
public class demo05 implements Runnable{ private int ticketcount = 100; @Override public void run() { while (true) { if ("窗口一".equals(Thread.currentThread().getName())) { //同步方法 if (synchronizedMethod()){ break; } } if ("窗口二".equals(Thread.currentThread().getName())) { synchronized (this) { //同步代码块 if (ticketcount == 0) { break; } else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } ticketcount--; System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩下" + ticketcount + "张"); } } } } } private synchronized boolean synchronizedMethod() { if (ticketcount == 0){ return true; }else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } ticketcount--; System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩下" + ticketcount + "张"); return false; } } }
具体上锁和未锁
if ("窗口二".equals(Thread.currentThread().getName())) { lock.lock(); try { //同步代码块 if (ticketcount == 0) { break; } else { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } ticketcount--; System.out.println(Thread.currentThread().getName() + "卖了一张票,还剩下" + ticketcount + "张"); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock(); } }
1. Class aClass = Class.forName("practice.reflect.Student"); 2.类名.getclass(); 3.new
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8P2Y8vLD-1631271826451)(C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20210907160300846.png)]
public static void main(String[] args) throws Exception{ Class aClass = Class.forName("practice.reflect.Student"); //获取所有的构造方法 Student student2 = (Student) aClass.newInstance(); Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } System.out.println("-----"); //获取指定参数的构造方法,忽略权限 Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class); System.out.println(declaredConstructor); //设置可访问、可使用、可创建对象(取消临时检查) declaredConstructor.setAccessible(true); Student student =(Student) declaredConstructor.newInstance(15); }
public static void main(String[] args) throws Exception{ Class aClass = Class.forName("practice.reflect.Student"); //获取所有的公共属性 Field[] fields = aClass.getFields(); for (Field field : fields) { System.out.println(field); } //获取所有的成员属性 System.out.println("--------分隔符---------------"); Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } //获取指定 System.out.println("--------分隔符---------------"); System.out.println(aClass.getDeclaredField("name")); System.out.println("--------分隔符---------------"); System.out.println(aClass.getDeclaredField("money")); /* Student stu1 = new Student(); stu1.setName("张三"); Student stu2 = new Student(); stu2.getName(); */ Object obj = aClass.getConstructor().newInstance(); aClass.getField("name").set(obj,"张三"); System.out.println(aClass.getField("name").get(obj)); }
public static void main(String[] args) throws Exception { //获取class类 Class aClass = Class.forName("practice.reflect.Student"); //获取对象 Object o = aClass.newInstance(); //获取method Method test = aClass.getMethod("test",String.class); //执行方法 test.invoke(o,"123456"); }
public static void main(String[] args) throws Exception{ //创建properties对象 Properties prop = new Properties(); //将配置文件的流加载 prop.load( demo04.class.getClassLoader().getResourceAsStream("a.properties")); //获取class类 Class className = Class.forName(prop.getProperty("className")); //创建class类对象 Object o = className.newInstance(); //通过对象获取方法 Method methodName = className.getDeclaredMethod(prop.getProperty("MethodName"),String.class); //执行方法 methodName.invoke(o,"123456789"); }
//第一种:引入本地文件dtd <!DOCTYPE 根节点名字 SYSTEM '文件名.dtd'> //第二种:在xml源文件中写 <!DOCTYPE 根节点名字 [约束内容]> //第三种:引入网络中的dtd <!DOCTYPE 根节点名字 PUBLIC "dtd文件的名称" "dtd文档的URL">
1.定义一个元素的格式为:<!ELEMENT 元素名 元素类型>
简单元素∶
EMPTY: 表示标签体为空
ANY:表示标签体可以为空也可以不为空
PCDATA:表示该元素的内容部分为字符串
复杂元素∶
直接写子元素名称。
多个子元素可以使用",“或者”|“隔开;”,"表示定义子元素的顺序;
"|":表示子元素只能出现任意一个
"?"零次或一次,
"+"一次或多次,
"*"零次或多次;
如果不写则表示出现一次
例:
定义一个属性的格式为︰<!ATTLIST 元素名称 属性名称 属性的类型 属性的约束>
属性的类型:
CDATA类型:普通的字符串
属性的约束∶
#REQUIRED :必须的
#IMPLIED :属性不是必需的
#FIXED value :属性值是固定的
1.所有枚举类都是Enum的子类
2.我们可以通过”枚举类名.枚举项名称"去访问指定的枚举项
3.每一个枚举项其实就是该枚举的一个对象
4.枚举也是一个类,也可以去定义成员变量
5.枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
6.枚举类可以有构造器,但必须是private的,它默认的也是private的。枚举项的用法比较特殊:枚举("");
7.枚举类也可以有抽象方法,但是枚举项必须重写该方法
ng.class);
//执行方法
methodName.invoke(o,“123456789”);
}