Java快速入门
Java基础语法
Java基础语法
类型转换
运算符
键盘录入技术
程序流程控制
程序流程控制是控制代码怎么去执行的
顺序结构
代码按照顺便正常执行
分支结构
循环结构
跳转关键字(break,continue)
随机数Random类
数组
作用
一个容器,用于在程序中存储一批同种类型的数据
定义
遍历
常见问题
方法
作用
封装一段代码的语法结构,可以被重复调用,以此提高代码的复用性,提高开发效率,让程序逻辑更清晰
定义格式
修饰符 返回值类型 方法名(形参列表){
方法体代码(需要执行的功能代码)
return 返回值;
}
//如果方法没有返回结果,返回值类型申明为:void
//方法需要调用才能执行
注意事项
方法重载
return
跳出并立即结束当前方法的执行
面向对象编程(oop)
定义(思想)
java 万物皆对象
创建对象
构造器
this关键字
封装
常用API(String、ArrayList)
String
ArrayList
static
饿汉单例代码示例:
/**
使用饿汉单例实现单例类
*/
public class SingleInstance {
/**
2、饿汉单例是在获取对象前,对象已经提前准备好了一个。
这个对象只能是一个,所以定义静态成员变量记住。
*/
public static SingleInstance instance = new SingleInstance();
/**
1、必须把构造器私有化。
*/
private SingleInstance(){
}
}
懒汉单例代码示例:
/**
懒汉单例
*/
public class SingleInstance2 {
/**
2、定义一个静态的成员变量负责存储一个对象。
只加载一次,只有一份。
注意:最好私有化,这样可以避免给别人挖坑!
*/
private static SingleInstance2 instance;
/**
3、提供一个方法,对外返回单例对象。
*/
public static SingleInstance2 getInstance() {
if(instance == null){
// 第一次来拿对象 :此时需要创建对象。
instance = new SingleInstance2();
}
return instance;
}
/**
1、私有化构造器
*/
private SingleInstance2(){
}
}
继承
权限修饰符
final
常量
枚举
抽象类
接口
多态
定义
- 多态是同一个行为具有不同的表现形式或形态的能力
- 同一方法可以根据发送对象的不同而采用不同的行为方式
- 多态就是事物的多种形态,一个对象在不同条件下所表现的不同形式
存在条件
- 继承或实现:在多态中必须存在有继承或实现关系的子类和父类
- 方法的重写:子类对父类中的某些方法进行重新定义(重写,使用@Override注解进行重写)
- 基类引用指向派生类对象,即父类引用指向子类对象,父类类型:指子类对象继承的父类类型,或实现的父接口类型
格式
父类类型 变量名 = new 子类类型();
然后通过 变量名.方法名()调用在子类中重写的方法
多态体现为父类引用变量可以指向子类对象:定义了一个父类类型的引用,指向新建的子类类型的对象,由于子类是继承他的父类的,所以父类类型的引用是可以指向子类类型的对象的
特点
- 多态情况下,子类和父类存在同名的成员变量时,访问的时父类的成员变量
- 多态情况下,子父类存在同名的非静态成员方法时,访问的是子类中重写的方法
- 多态情况下,子父类存在同名的静态成员变量成员方法时,访问的是父类的成员函数
- 多态情况下,不能访问子类独由的方法
instanceof关键字
格式
变量名 instanceof 数据类型
//如果变量属于该数据类型或者其子类型,返回true
//如果变量不属于该数据类或者其子类型,返回false
代码示例
public class DemoApplication {
public static void main(String[] args) {
//向上转型
//父类类型 对象 = new 子类类型()
Animal animal = new Cat();
//向下转型
//子类类型 子类变量名 = (子类类型) 父类变量名
if ( animal instanceof Cat){
Cat cat = (Cat) animal;
cat.sleep();
}else if(animal instanceof Dog){
Dog dog = (Dog) animal;
dog.walk();
}
}
}
集合
- 数组的长度是固定的。集合的长度是可变的。
- 数组中存储的是同一类型的元素,可以存储基本数据类型值。集合存储的都是对象。而且对象的类型可以不一致。在开发中一般当对象多的时候,使用集合进行存储。
Colloction
Colloction常用API
public boolean add(E e): 把给定的对象添加到当前集合中 。
public void clear():清空集合中所有的元素。
public boolean remove(E e): 把给定的对象在当前集合中删除。
public boolean contains(Object obj): 判断当前集合中是否包含给定的对象。
public boolean isEmpty(): 判断当前集合是否为空。
public int size(): 返回集合中元素的个数。
public Object[] toArray(): 把集合中的元素,存储到数组中
Iterator 迭代器
迭代:即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。这种取出方式专业术语称为迭代。
常用方法
public E next():返回迭代的下一个元素。
public boolean hasNext():如果仍有元素可以迭代,则返回 true。
代码示例
public class IteratorDemo {
public static void main(String[] args) {
// 使用多态方式 创建对象
Collection<String> coll = new ArrayList<String>();
// 添加元素到集合
coll.add("串串星人");
coll.add("吐槽星人");
coll.add("汪星人");
//遍历
//使用迭代器 遍历 每个集合对象都有自己的迭代器
Iterator<String> it = coll.iterator();
// 泛型指的是 迭代出 元素的数据类型
while(it.hasNext()){ //判断是否有迭代元素
String s = it.next();//获取迭代出的元素
System.out.println(s);
}
}
}
//注意,如果集合没有元素使用迭代器的next的方法会java.util.NoSuchElementException没有集合元素的错误。
删除元素
常用在集合Collection的remove方法无法根据条件删除
代码示例:
@Test
public void test02(){
Collection<String> coll = new ArrayList<>();
coll.add("陈琦");
coll.add("李晨");
coll.add("邓超");
coll.add("黄晓明");
//删除名字有三个字的
// coll.remove(o)//无法编写
Iterator<String> iterator = coll.iterator();
while(iterator.hasNext()){
String element = iterator.next();
if(element.length()==3){
// coll.remove(element);//错误的
iterator.remove();
}
}
System.out.println(coll);
}
增强for
示例:
for(元素的数据类型 变量 : Collection集合or数组){
//写操作代码
}
List
特点
- List集合所有的元素是以一种线性方式进行存储的,例如,存元素的顺序是11、22、33。那么集合中,元素的存储就是按照11、22、33的顺序完成的)
- 它是一个元素存取有序的集合。即元素的存入顺序和取出顺序一致。
- 它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素(与数组的索引是一个道理)。
- 集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
常用方法
1.添加元素
void add(int index, E ele)
boolean addAll(int index, Collection<? extends E> eles)
2、获取元素
E get(int index)
List subList(int fromIndex, int toIndex)
3、获取元素索引
int indexOf(Object obj)
int lastIndexOf(Object obj)
4、删除和替换元素
E remove(int index)
E set(int index, E ele)
实现类
ArrayList集合
java.util.ArrayList
集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList
是最常用的集合。
代码示例
class Example2{
public static void main(String[] args) {
ArrayList arrayList = new ArrayList();
arrayList.add("a");
arrayList.add("b");
arrayList.add("c");
System.out.println("arrayList的元素为:"+arrayList);
arrayList.set(0,"c"); //将索引为0的位置对象a修改为对象c
System.out.println("arrayList的元素为"+arrayList);
arrayList.add(1,"e"); //将对象e添加到索引为1的位置
System.out.print("arrayList的元素为:");
for (int i=0;i<arrayList.size();i++){
System.out.print(arrayList.get(i));//for循环迭代arrayList集合元素
}
System.out.println("");
System.out.println("arrayList指定元素c位置的索引为"+arrayList.indexOf("c"));
//返回列表中指定元素c位置的索引
System.out.println("arrayList指定元素c最后位置的索引为"+arrayList.lastIndexOf("c"));
//返回列表中指定元素c最后位置的索引
System.out.println("arrayList的指定区域为"+arrayList.subList(1,2));
//返回列表中指返回一个指定区域的List集合对象[1,2)
}
}
LinkedList集合
java.util.LinkedList
集合数据存储的结构是链表结构(双链表)。方便元素添加、删除的集合。
代码示例
public class Example3 {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList();
linkedList.add("a");
linkedList.add("b");
linkedList.add("c");
linkedList.add("d");
//获得并输入列表开头的对象
System.out.println("列表开头元素为:"+linkedList.getFirst()+"列表结尾元素为:"+linkedList.getLast());
linkedList.addFirst("rr"); //向列表开头添加一个对象
System.out.println("列表中所有元素:"+linkedList);
linkedList.removeLast();//移除列表结尾元素
System.out.println("列表结尾元素为:"+linkedList.getLast());
//获取并输出列表结尾的对象
}
}
Listlterator
List 集合额外提供了一个 listIterator() 方法,该方法返回一个 ListIterator 对象, ListIterator 接口继承了 Iterator 接口,提供了专门操作 List 的方法:
代码示例
public static void main(String[] args) {
List<Student> c = new ArrayList<>();
c.add(new Student(1,"张三"));
c.add(new Student(2,"李四"));
c.add(new Student(3,"王五"));
c.add(new Student(4,"赵六"));
c.add(new Student(5,"钱七"));
//从指定位置往前遍历
ListIterator<Student> listIterator = c.listIterator(c.size());
while(listIterator.hasPrevious()){
Student previous = listIterator.previous();
System.out.println(previous);
}
}
Set
特点
- 特点:无序,不重复
- 遍历:foreach,迭代器
- 扩容: 初始容量16,负载因子0.75,扩容增量1倍
实现类
HsshSet
特点
- 它存储唯一元素并允许空值,依据对象的hashcode来确定该元素是否存在
- 由HashMap支持
- 不保持插入顺序(无序)
- 非线程安全
- 性能参数:初始容量,负载因子,默认值: 初始容量16,负载因子0.75,示例:new HashSet<>(20, 0.5f);
注意
HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法比较相等,并且两个对象的 equals() 方法返回值也相等。因此,存储到HashSet的元素要重写hashCode和equals方法。
LinkedHashSet
LinkedHashSet是HashSet的子类,它在HashSet的基础上,在结点中增加两个属性before和after维护了结点的前后添加顺序。
java.util.LinkedHashSet
,它是链表和哈希表组合的一个数据存储结构。LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。(保持插入顺序)
TreeSet
特点
- 是一个包含有序的且没有重复元素的集合
- 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序
- TreeSet是基于TreeMap实现的
代码示例
//演示两种自定义排序方法
//1. 较器通过构造函数传入比
TreeSet<Integer> tset = new TreeSet<Integer>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
return o2 - o1;
}
});
//2.对象类中定义
@Override
public int compareTo(Student o) {
if (this.getAge() - o.getAge() == 0) {
return this.getSid() - o.getSid();
}
return this.getAge() - o.getAge();
}
Map
概述
现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射。Java提供了专门的集合类用来存放这种对象关系的对象,即java.util.Map<K,V>接口。
我们通过查看Map接口描述,发现Map<K,V>接口下的集合与Collection<E>接口下的集合,它们存储数据的形式不同。
- Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。
- Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值。
- Collection中的集合称为单列集合,Map中的集合称为双列集合。
- 需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值(这个值可以是单个值,也可以是个数组或集合值)。
常用API
public class MapDemo {
public static void main(String[] args) {
//创建 map对象
HashMap<String, String> map = new HashMap<String, String>();
//添加元素到集合
map.put("黄晓明", "杨颖");
map.put("文章", "马伊琍");
map.put("邓超", "孙俪");
System.out.println(map);
//String remove(String key)
System.out.println(map.remove("邓超"));
System.out.println(map);
// 想要查看 黄晓明的媳妇 是谁
System.out.println(map.get("黄晓明"));
System.out.println(map.get("邓超"));
}
}
//使用put方法时,若指定的键(key)在集合中没有,则没有这个键对应的值,返回null,并把指定的键值添加到集合中;
//若指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。
遍历
public class TestMap {
public static void main(String[] args) {
HashMap<String,String> map = new HashMap<>();
map.put("许仙", "白娘子");
map.put("董永", "七仙女");
map.put("牛郎", "织女");
map.put("许仙", "小青");
//单独遍历key和值
System.out.println("所有的key:");
Set<String> keySet = map.keySet();
for (String key : keySet) {
System.out.println(key);
}
System.out.println("所有的value:");
Collection<String> values = map.values();
for (String value : values) {
System.out.println(value);
}
//同时遍历key-value entrySet()
System.out.println("所有的映射关系");
Set<Map.Entry<String,String>> entrySet = map.entrySet();
for (Map.Entry<String,String> entry : entrySet) {
System.out.println(entry.getKey()+"->"+entry.getValue());
}
}
}
实现类
HashMap
HashMap线程不安全,允许使用null键和null值;Hashtable是线程安全的,任何非 null 对象都可以用作键或值。
LinkedHashMap
维护着一个运行于所有条目的双重链接列表。此链接列表定义了迭代顺序,该迭代顺序通常就是将键插入到映射中的顺序(插入顺序)。
TreeMap
基于红黑树(Red-Black tree)的 NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
package com.atguigu.map;
import java.util.Comparator;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import org.junit.Test;
public class TestTreeMap {
@Test
public void test1() {
TreeMap<String,Integer> map = new TreeMap<>();
map.put("Jack", 11000);
map.put("Alice", 12000);
map.put("zhangsan", 13000);
map.put("baitao", 14000);
map.put("Lucy", 15000);
//String实现了Comparable接口,默认按照Unicode编码值排序
Set<Entry<String, Integer>> entrySet = map.entrySet();
for (Entry<String, Integer> entry : entrySet) {
System.out.println(entry);
}
}
@Test
public void test2() {
//指定定制比较器Comparator,按照Unicode编码值排序,但是忽略大小写
TreeMap<String,Integer> map = new TreeMap<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o1.compareToIgnoreCase(o2);
}
});
map.put("Jack", 11000);
map.put("Alice", 12000);
map.put("zhangsan", 13000);
map.put("baitao", 14000);
map.put("Lucy", 15000);
Set<Entry<String, Integer>> entrySet = map.entrySet();
for (Entry<String, Integer> entry : entrySet) {
System.out.println(entry);
}
}
}
Collections工具类
Collections 是一个操作 Set、List 和 Map 等集合的工具类。Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法:
public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,而且支持自然排序
public static T max(Collection<? extends T> coll,Comparator<? super T> comp)在coll集合中找出最大的元素,集合中的对象必须是T或T的子类对象,按照比较器comp找出最大者
public static void reverse(List<?> list)反转指定列表List中元素的顺序。
public static void shuffle(List<?> list) List 集合元素进行随机排序,类似洗牌
public static <T extends Comparable<? super T>> void sort(List list)根据元素的自然顺序对指定 List 集合元素按升序排序
public static void sort(List list,Comparator<? super T> c)根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
public static void swap(List<?> list,int i,int j)将指定 list 集合中的 i 处元素和 j 处元素进行交换
public static int frequency(Collection<?> c,Object o)返回指定集合中指定元素的出现次数
public static void copy(List<? super T> dest,List<? extends T> src)将src中的内容复制到dest中
public static boolean replaceAll(List list,T oldVal,T newVal):使用新值替换 List 对象的所有旧值
Stream
Stream流是对集合(Collection)对象功能的增强,与Lambda表达式结合,可以提高编程效率、间接性和程序可读性。
特点
1、代码简洁:函数式编程写出的代码简洁且意图明确,使用stream接口让你从此告别for循环
2、多核友好:Java函数式编程使得编写并行程序如此简单,就是调用一下方法
流程
创建流
Stream创建
Stream<Integer> stream1 = Stream.of(1,2,3,4,5);
Collection集合创建(应用中最常用的一种)
List<Integer> integerList = new ArrayList<>();
integerList.add(1);
integerList.add(2);
integerList.add(3);
integerList.add(4);
integerList.add(5);
Stream<Integer> listStream = integerList.stream();
Array数组创建
int[] intArr = {1, 2, 3, 4, 5};
IntStream arrayStream = Arrays.stream(intArr);
通过Arrays.stream方法生成流,并且该方法生成的流是数值流【即IntStream】而不是 Stream
注:
使用数值流可以避免计算过程中拆箱装箱,提高性能。
Stream API提供了mapToInt、mapToDouble、mapToLong三种方式将对象流【即Stream 】转换成对应的数值流,同时提供了boxed方法将数值流转换为对象流
文件创建
try {
Stream<String> fileStream = Files.lines(Paths.get("data.txt"), Charset.defaultCharset());
} catch (IOException e) {
e.printStackTrace();
}
//把流创建在try(){}的()里可以在结束时自动关闭该流
通过Files.line方法得到一个流,并且得到的每个流是给定文件中的一行
函数创建
iterator
Stream<Integer> iterateStream = Stream.iterate(0, n -> n + 2).limit(5);
iterate方法接受两个参数,第一个为初始化值,第二个为进行的函数操作,因为iterator生成的流为无限流,通过limit方法对流进行了截断,只生成5个偶数
generator
Stream<Double> generateStream = Stream.generate(Math::random).limit(5);
generate方法接受一个参数,方法参数类型为Supplier ,由它为流提供值。generate生成的流也是无限流,因此通过limit对流进行了截断
操作流
中间操作符
//1、filter:输出ID大于6的user对象(过滤)
List<User> filetrUserList = userList.stream().filter(user -> user.getId() > 6).collect(Collectors.toList());
filetrUserList.forEach(System.out::println);
//2、map
List<String> mapUserList = userList.stream().map(user -> user.getName() + "用户").collect(Collectors.toList());
mapUserList.forEach(System.out::println);
//3、distinct:去重
//User::getCity() 完全写法为:user -> user.getCity()
List<String> distinctUsers = userList.stream().map(User::getCity).distinct().collect(Collectors.toList());
distinctUsers.forEach(System.out::println);
//4、sorted:排序,根据名字倒序
userList.stream().sorted(Comparator.comparing(User::getName).reversed()).collect(Collectors.toList()).forEach(System.out::println);
//5、limit:取前5条数据
userList.stream().limit(5).collect(Collectors.toList()).forEach(System.out::println);
//6、skip:跳过第几条取后几条
userList.stream().skip(7).collect(Collectors.toList()).forEach(System.out::println);
//7、flatMap:数据拆分一对多映射
userList.stream().flatMap(user -> Arrays.stream(user.getCity().split(","))).forEach(System.out::println);
//8、peek:对元素进行遍历处理,每个用户ID加1输出
userList.stream().peek(user -> user.setId(user.getId()+1)).forEach(System.out::println);
终端操作符
//1、collect:收集器,将流转换为其他形式
Set set = userList.stream().collect(Collectors.toSet());
set.forEach(System.out::println);
System.out.println("--------------------------");
List list = userList.stream().collect(Collectors.toList());
list.forEach(System.out::println);
//2、forEach:遍历流
userList.stream().forEach(user -> System.out.println(user));
userList.stream().filter(user -> "上海".equals(user.getCity())).forEach(System.out::println);
//3、findFirst:返回第一个元素
User firstUser = userList.stream().findFirst().get();
User firstUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findFirst().get();
//4、findAny:将返回当前流中的任意元素
User findUser = userList.stream().findAny().get();
User findUser1 = userList.stream().filter(user -> "上海".equals(user.getCity())).findAny().get();
//5、count:返回流中元素总数
long count = userList.stream().filter(user -> user.getAge() > 20).count();
System.out.println(count);
//6、sum:求和
int sum = userList.stream().mapToInt(User::getId).sum();
//7、max:最大值
int max = userList.stream().max(Comparator.comparingInt(User::getId)).get().getId();
//8、min:最小值
int min = userList.stream().min(Comparator.comparingInt(User::getId)).get().getId();
//9、anyMatch:检查是否至少匹配一个元素
boolean matchAny = userList.stream().anyMatch(user -> "北京".equals(user.getCity()));
//10、allMatch:检查是否匹配所有元素
boolean matchAll = userList.stream().allMatch(user -> "北京".equals(user.getCity()));
//11、noneMatch:检查是否没有匹配所有元素,返回boolean
boolean nonaMatch = userList.stream().allMatch(user -> "云南".equals(user.getCity()));
//12、reduce:将流中元素反复结合起来,得到一个值
Optional reduce = userList.stream().reduce((user, user2) -> {
return user;
});
if(reduce.isPresent()) System.out.println(reduce.get());
Collect收集
//1.toList() 将用户ID存放到List集合中
List<Integer> idList = userList.stream().map(User::getId).collect(Collectors.toList()) ;
//2.toMap() 将用户ID和Name以Key-Value形式存放到Map集合中
Map<Integer,String> userMap = userList.stream().collect(Collectors.toMap(User::getId,User::getName));
//3.toSet() 将用户所在城市存放到Set集合中
Set<String> citySet = userList.stream().map(User::getCity).collect(Collectors.toSet());
//4.counting() 符合条件的用户总数
long count = userList.stream().filter(user -> user.getId()>1).collect(Collectors.counting());
//5.summingInt() 对结果元素即用户ID求和
Integer sumInt = userList.stream().filter(user -> user.getId()>2).collect(Collectors.summingInt(User::getId)) ;
//6.minBy() 筛选元素中ID最小的用户
User maxId = userList.stream().collect(Collectors.minBy(Comparator.comparingInt(User::getId))).get() ;
//7.joining() 将用户所在城市,以指定分隔符链接成字符串;
String joinCity = userList.stream().map(User::getCity).collect(Collectors.joining("||"));
//8.groupingBy() 按条件分组,以城市对用户进行分组;
Map<String,List<User>> groupCity = userList.stream().collect(Collectors.groupingBy(User::getCity));
异常
try(
//此处使用如stream流之类的需要使用后关闭的
){
//此处使用正常的主体代码
}catch(Exception e){
//打印异常或写入日志
}finally{
//不管程序是否异常,这里都会执行
}
File和IO流
File对象
创建File对象
public static void main(String[] args) {
//创建一个File对象 并指定文件得路径 \转移字符串
//第一种Windows通用两种分隔符
File file01 = new File("D:\\AAA\\aaa.txt");
File file02 = new File("D:/AAA/bbb.txt");
// 第二种 File.separator根据当前代码所在得系统自动获取相应得分割符
System.out.println(File.separator); // \因为我们当前在window下
File file03 = new File("D:"+File.separator+"AAA"+File.separator+"ccc.txt");
添加文件
//创建文件对象
File file = new File("F:/AAA/a.txt");
//添加文件操作
file.createNewFile();
File file2 = new File("F:/AAA/bbb");
file2.mkdir();//创建单层文件夹
File file3 = new File("F:/AAA/bbb/ccc");
file3.mkdirs();//创建多层文件夹
删除操作
//创建文件对象
File file = new File("F:/AAA/a.txt");
//删除操作
file.delete();//删除文件,同时可以删除空的文件夹
file3.deleteOnExit();//程序退出时删除文件
修改文件
//创建文件对象
File file = new File("F:/AAA/a.txt");
//修改操作
file.setReadable(false);//修改能否打开文件的权限
file.setWritable(false);//修改能否修改文件中的内容的权限
file.setReadOnly();//修改文件为只读
file.renameTo(new File("D:/AAA/aaa.txt"));//给文件重命名
查询文件
//创建文件对象
File file = new File("F:/AAA/a.txt");
//查询操作
String name = file.getName();//获取文件名称
String parent = file.getParent();//获取父级的名称
String path = file.getPath();//获取路径
System.out.println(name + " "+ parent+" "+path);
boolean f1 = file.isFile();//是否为文件类型
boolean f2 = file.isDirectory();//是否为文件夹类型
System.out.println(f1 + " "+f2);
遍历
public class test {
public static void main(String[] args) {
String[] s=new String[100];
File f=new File("D:/个人文件");
s=f.list(); //获取当前目录下所有的一级文件名称到一个字符串数组中返回
for(String ss:s){
System.out.println(ss);
}
File[] s1=new File[100];
File f1=new File("D:/个人文件");
s1=f1.listFiles();//获取当前目录下所有的一级文件对象到一个对象数组中返回(重点)
for(File ss1:s1){
System.out.println(ss1);
}
}
}
IO流
IO流即输入输出流,用于处理数据的传输
字符集编码、解码操作
字节流
字节流基类
字节输入流(InputStream)
常用方法:
// 从输入流中读取数据的下一个字节
abstract int read()
// 从输入流中读取一定数量的字节,并将其存储在缓冲区数组 b中
int read(byte[] b)
// 将输入流中最多 len 个数据字节读入 byte 数组
int read(byte[] b, int off, int len)
// 跳过和丢弃此输入流中数据的 n个字节
long skip(long n)
// 关闭此输入流并释放与该流关联的所有系统资源
void close()
字节输出流(OutputStream)
常用方法:
// 将 b.length 个字节从指定的 byte 数组写入此输出流
void write(byte[] b)
// 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流
void write(byte[] b, int off, int len)
// 将指定的字节写入此输出流
abstract void write(int b)
// 关闭此输出流并释放与此流有关的所有系统资源
void close()
// 刷新此输出流并强制写出所有缓冲的输出字节
void flush()
字节文件操作流
字节文件输入流(FileInputStream)
构造方法:
// 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的File对象file指定
FileInputStream(File file)
// 通过打开一个到实际文件的连接来创建一个FileInputStream,该文件通过文件系统中的路径name指定
FileInputStream(String name)
//示例(使用字节数组)
//构造方法
InputStream inputStream2 = new FileInputStream("f://hello/test.txt");
// 字节数组
byte[] b = new byte[2];
int i2 = 0;
// 一次读取一个字节数组
while ((i2 = inputStream2.read(b)) != -1) {
System.out.print(new String(b, 0, i2) + " ");// AB CD
}
//关闭IO流
inputStream2.close();
字节文件输出流(FileOutputStream)
构造方法:
// 创建一个向指定File对象表示的文件中写入数据的文件输出流
FileOutputStream(File file)
// 创建一个向指定File对象表示的文件中写入数据的文件输出流
FileOutputStream(File file, boolean append)
// 创建一个向具有指定名称的文件中写入数据的输出文件流
FileOutputStream(String name)
// 创建一个向具有指定name的文件中写入数据的输出文件流
FileOutputStream(String name, boolean append)
OutputStream outputStream = new FileOutputStream(new File("test.txt"));
// 写出数据
outputStream.write("ABCD".getBytes());
// 关闭IO流
outputStream.close();
// 内容追加写入
OutputStream outputStream2 = new FileOutputStream("test.txt", true);
// 输出换行符
outputStream2.write("\r\n".getBytes());
// 输出追加内容
outputStream2.write("hello".getBytes());
// 关闭IO流
outputStream2.close();
字节缓冲流(高级流)
字节缓存输入流(BufferedInputStream)
构造方法:
// 创建一个 BufferedInputStream并保存其参数,即输入流in,以便将来使用。
BufferedInputStream(InputStream in)
// 创建具有指定缓冲区大小的 BufferedInputStream并保存其参数,即输入流in以便将来使用
BufferedInputStream(InputStream in, int size)
//示例
InputStream in = new FileInputStream("test.txt");
// 字节缓存流
BufferedInputStream bis = new BufferedInputStream(in);
byte[] bs = new byte[20];
int len = 0;
while ((len = bis.read(bs)) != -1) {
System.out.print(new String(bs, 0, len));
}
// 关闭流
bis.close();
字节缓存输出流(BufferedOutputStream)
构造方法:
// 创建一个新的缓冲输出流,以将数据写入指定的底层输出流
BufferedOutputStream(OutputStream out)
// 创建一个新的缓冲输出流,以将具有指定缓冲区大小的数据写入指定的底层输出流
BufferedOutputStream(OutputStream out, int size)
常用方法:
// 将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流
void write(byte[] b, int off, int len)
// 将指定的字节写入此缓冲的输出流
void write(int b)
// 刷新此缓冲的输出流
void flush()
//示例
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("test.txt", true));
// 输出换行符
bos.write("\r\n".getBytes());
// 输出内容
bos.write("Hello Android".getBytes());
// 刷新此缓冲的输出流
bos.flush();
// 关闭流
bos.close();
字符流
字符流基类
字符输入流(Reader)
常用方法:
// 读取单个字符
int read()
// 将字符读入数组
int read(char[] cbuf)
// 将字符读入数组的某一部分
abstract int read(char[] cbuf, int off, int len)
// 跳过字符
long skip(long n)
// 关闭该流并释放与之关联的所有资源
abstract void close()
字符输出流(Write)
常用方法:
// 写入字符数组
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)
// 将指定字符添加到此 writer
Writer append(char c)
// 将指定字符序列添加到此 writer
Writer append(CharSequence csq)
// 将指定字符序列的子序列添加到此 writer.Appendable
Writer append(CharSequence csq, int start, int end)
// 关闭此流,但要先刷新它
abstract void close()
// 刷新该流的缓冲
abstract void flush()
字符转换流
InputStreamReader(字节流转字符流)
构造方法:
// 创建一个使用默认字符集的 InputStreamReader
InputStreamReader(InputStream in)
// 创建使用给定字符集的 InputStreamReader
InputStreamReader(InputStream in, Charset cs)
// 创建使用给定字符集解码器的 InputStreamReader
InputStreamReader(InputStream in, CharsetDecoder dec)
// 创建使用指定字符集的 InputStreamReader
InputStreamReader(InputStream in, String charsetName)
特有方法:
//返回此流使用的字符编码的名称
String getEncoding()
//代码示例
//使用默认编码
InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt"));
int len;
while ((len = reader.read()) != -1) {
System.out.print((char) len);//爱生活,爱Android
}
reader.close();
//指定编码
InputStreamReader reader = new InputStreamReader(new FileInputStream("test.txt"),"utf-8");
int len;
while ((len = reader.read()) != -1) {
System.out.print((char) len);//????????Android
}
reader.close();
OutputStreamWriter(字节流转字符流)
构造方法:
// 创建使用默认字符编码的 OutputStreamWriter
OutputStreamWriter(OutputStream out)
// 创建使用给定字符集的 OutputStreamWriter
OutputStreamWriter(OutputStream out, Charset cs)
// 创建使用给定字符集编码器的 OutputStreamWriter
OutputStreamWriter(OutputStream out, CharsetEncoder enc)
// 创建使用指定字符集的 OutputStreamWriter
OutputStreamWriter(OutputStream out, String charsetName)
特有方法:
//返回此流使用的字符编码的名称
String getEncoding()
字符缓冲流
BufferedReader
构造方法:
// 创建一个使用默认大小输入缓冲区的缓冲字符输入流
BufferedReader(Reader in)
// 创建一个使用指定大小输入缓冲区的缓冲字符输入流
BufferedReader(Reader in, int sz)
特有方法:
// 读取一个文本行
String readLine()
//代码示例
//生成字符缓冲流对象
BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream("test.txt")));
String str;
//一次性读取一行
while ((str = reader.readLine()) != null) {
System.out.println(str);// 爱生活,爱Android
}
//关闭流
reader.close();
BufferedWriter
构造方法:
// 创建一个使用默认大小输出缓冲区的缓冲字符输出流
BufferedWriter(Writer out)
// 创建一个使用给定大小输出缓冲区的新缓冲字符输出流
BufferedWriter(Writer out, int sz)
特有方法:
// 写入一个行分隔符
void newLine()
线程
创建线程:
方式一
方式二
匿名写法:
方式三
三种方式对比总结
线程
Thread常用方法、构造器
线程安全问题
原因:多个线程同时访问同一个共享资源且存在修改该资源
解决方案:加锁,把共享资源进行上锁,每次只能一个线程进入访问完毕以后解锁,然后其他线程才能进来
同步代码块:
synchronized(同步锁对象){
操作共享资源的代码(核心代码)
}
锁对象规范要求:
同步方法:
同步代码块与同步方法:同步代码块锁的范围更小,同步方法锁的范围更大。
Lock锁:
线程通信
线程池(重点)
定时器
Timer定时器:本身是一个单线程
ScheduledExecutorService定时器:多线程,基于线程池
并发、并行
并发:CPU分时轮询的执行线程
并行:同一时刻同时在执行
线程的生命周期
网络编程(通信)
实现网络编程关键的三要素
IP
端口号
协议
网络通信协议:连接和通信数据的规则
UDP协议
代码示例(默认支持多个客户端)
//客户端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) throws Exception {
//1.创建发送端对象:发送端自带默认的端口号(人)
DatagramSocket socket = new DatagramSocket();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入发送的消息:");
String msg = sc.nextLine();
if ("exit".equals(msg)) {
System.out.println("离线成功!");
socket.close();
break;
}
//2.创建一个数据包对象封装数据
byte[] buffer = msg.getBytes();
//封装发送的数据(字节)、发送数据的大小、服务端IP地址(本次使用的是本机)、服务端端口
DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLoopbackAddress(), 8888);
//3.发送数据
socket.send(packet);
}
}
}
//服务端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class SercerDemo1 {
public static void main(String[] args) throws Exception {
//1.创建接收端对象:注册端口
DatagramSocket socket = new DatagramSocket(8888);
//2.创建一个数据包对象接收数据
byte[] buffer = new byte[1024 * 64];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
while (true) {
//3.等待接收数据
socket.receive(packet);
//4.取出数据
//读取多少取多少
int len = packet.getLength();
String rs = new String(buffer, 0, len);
System.out.println("收到了来自:" + packet.getAddress() + ",对方端口是:" + packet.getPort() + "的消息:" + rs);
}
}
}
广播、组播
TCP协议
代码示例(默认不支持多个客户端)
-->需要使用多线程去完成处理多个客户端消息(只需服务端进行多线程修改)
//客户端
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) {
try {
//1.创建Socket通信管道请求服务端连接
//服务端IP地址、服务端端口
Socket socket = new Socket("127.0.0.1", 8888);
//2.从socket通讯管道中得到一个字节输出流,负责发送
OutputStream os = socket.getOutputStream();
//3.把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入你想要发送的消息:");
String msg = sc.nextLine();
//4.发送消息并刷新
ps.println(msg); //注意这里必须至少要一行消息,所有需要使用println
ps.flush();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//服务端
import java.net.ServerSocket;
import java.net.Socket;
public class ServerDemo1 {
public static void main(String[] args) {
//1.注册端口
try {
ServerSocket serverSocket = new ServerSocket(7777);
//a.定义一个死循环由主线程负责不断地接收客户端的Socket管道连接
while (true) {
//2.必须调用accept方法:等待接受客户端的Socket连接请求,建立Socket通信管道
Socket socket = serverSocket.accept();
//用于客户端上线提醒
System.out.println(socket.getRemoteSocketAddress() + "上线了!");
//下面注释代码为不使用线程只能一个客户端使用的情况
// //3.从socket通信管道中得到一个字节输入流
// InputStream is = socket.getInputStream();
// //4.把字节输入流1包装成缓冲字符输入流进行消息接收
// BufferedReader br = new BufferedReader(new InputStreamReader(is));
// //5.按照行读取消息
// String msg;
// while ((msg = br.readLine()) != null) {
// System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
// }
//3.开始创建独立线程处理Socket
new ServerReaderThread(socket).start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//线程类(ServerReaderThread.java)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//3.从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//4.把字节输入流1包装成缓冲字符输入流进行消息接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
}
} catch (Exception e) {
//可以用于客户端下线了提醒
System.out.println(socket.getRemoteSocketAddress() + "下线了!");
}
}
}
使用线程池代码示例
//客户端(和之前一样)
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) {
try {
//1.创建Socket通信管道请求服务端连接
//服务端IP地址、服务端端口
Socket socket = new Socket("127.0.0.1", 7777);
//2.从socket通讯管道中得到一个字节输出流,负责发送
OutputStream os = socket.getOutputStream();
//3.把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入你想要发送的消息:");
String msg = sc.nextLine();
//4.发送消息并刷新
ps.println(msg); //注意这里必须至少要一行消息,所有需要使用println
ps.flush();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//服务端(使用线程池,完成服务端可以同时处理多个客户端消息)
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.*;
public class ServerDemo1 {
//使用静态变量记住一个线程池对象
private static ExecutorService pool = new ThreadPoolExecutor(3, 5, 6, TimeUnit.SECONDS, new ArrayBlockingQueue<>(2),
Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) {
try {
//1.注册端口
ServerSocket serverSocket = new ServerSocket(7777);
while (true) {
//2.每接收到一个客户端的Socket管道
Socket socket = serverSocket.accept();
System.out.println(socket.getRemoteSocketAddress() + "上线了!");
Runnable target = new ServerReaderRunnable(socket);
pool.execute(target);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//线程池类(ServerReaderRunnable.java)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ServerReaderRunnable implements Runnable {
private Socket socket;
public ServerReaderRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//3.从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//4.把字节输入流1包装成缓冲字符输入流进行消息接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
}
} catch (Exception e) {
//可以用于客户端下线了提醒
System.out.println(socket.getRemoteSocketAddress() + "下线了!");
}
}
}
使用线程池优点:
实战案例-即时通信
//客户端
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;
public class ClientDemo1 {
public static void main(String[] args) {
try {
//1.创建Socket通信管道请求服务端连接
//服务端IP地址、服务端端口
Socket socket = new Socket("127.0.0.1", 7777);
//创建一个独立的线程专门负责这个客户端的读消息(服务端随时可发消息过来)
new ClientReaderThread(socket).start();
//2.从socket通讯管道中得到一个字节输出流,负责发送
OutputStream os = socket.getOutputStream();
//3.把低级的字节流包装成打印流
PrintStream ps = new PrintStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请输入你想要发送的消息:");
String msg = sc.nextLine();
//4.发送消息并刷新
ps.println(msg); //注意这里必须至少要一行消息,所有需要使用println
ps.flush();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//客户端线程类(ClientReaderThread.java)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Socket;
public class ClientReaderThread extends Thread {
private Socket socket;
public ClientReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//3.从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//4.把字节输入流1包装成缓冲字符输入流进行消息接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println("收到消息:" + msg);
}
} catch (Exception e) {
//可以用于客户端下线了提醒
System.out.println("服务端把你踢出去了");
}
}
}
//服务端
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
public class ServerDemo1 {
//定义一个静态的List集合存储当前全部在线的socket管道
public static List<Socket> allOnlineSockets = new ArrayList<>();
public static void main(String[] args) {
//1.注册端口
try {
ServerSocket serverSocket = new ServerSocket(7777);
//a.定义一个死循环由主线程负责不断地接收客户端的Socket管道连接
while (true) {
//2.必须调用accept方法:等待接受客户端的Socket连接请求,建立Socket通信管道
//注意,在这里等待客户端的socket管道连接
Socket socket = serverSocket.accept();
//用于客户端上线提醒
System.out.println(socket.getRemoteSocketAddress() + "上线了!");
allOnlineSockets.add(socket);
//3.开始创建独立线程处理Socket
new ServerReaderThread(socket).start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
//服务端线程类(ServerReaderThread.java)
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
public class ServerReaderThread extends Thread {
private Socket socket;
public ServerReaderThread(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
try {
//3.从socket通信管道中得到一个字节输入流
InputStream is = socket.getInputStream();
//4.把字节输入流包装成缓冲字符输入流进行消息接收
BufferedReader br = new BufferedReader(new InputStreamReader(is));
//5.按照行读取消息
String msg;
while ((msg = br.readLine()) != null) {
System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
//把消息进行端口转发给全部客户端socket管道
sendMsgToAll(msg);
}
} catch (Exception e) {
//可以用于客户端下线了提醒
System.out.println(socket.getRemoteSocketAddress() + "下线了!");
ServerDemo1.allOnlineSockets.remove(socket);
}
}
private void sendMsgToAll(String msg) throws Exception {
for (Socket socket : ServerDemo1.allOnlineSockets) {
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(msg);
ps.flush();
}
}
}
大杂烩
单元测试
*代码示例:
常用注解
反射
反射的作用
1.绕过编译阶段为集合添加数据
2.通用框架的底层原理
注解
自定义注解
元注解
用在自定义注解上面的注解,用于限制自定义注解
注解的解析
获取注解里的内容
动态代理
代理:某些场景下对象会找一个代理对象,来辅助自己完成一些工作
案例:通过代理实现方法性能统计
优点
XML
定义:可扩展标记语言,它是一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据
XML解析
使用Dom4j解析XML
Xpath检索出XML文件
评论