java 练习之路
(基础部分只有代码,就不放了,后面的图片很多也不弄了)
继承
定义 : 继承是面向对象的三大特征之一。可以使得子类具有父类的属性和方法,还可以在子类中重新定义,追加属性和方法
public class Fu{
public void show (){
System.out.println("show 被调用");
}
}
public class Zi extends Fu{
public void method(){
System.out.println("method 被调用");
}
}
继承的好处与弊端
好处
-
提高代码复用性
-
提高代码的维护性
弊端
- 继承让类与类之间产生了关系,类的耦合度增强了,当父类发生改变时子类实现也不得不跟着变化,削弱了子类的独立性
什么时候使用继承
假设法: 我有两个类A和B,如果他们满足A是B的一种,或者B是A的一种,就说明他们存在继承关系
super 关键字
用来访问父类的成员,如成员变量,成员方法及其构造方法
子类所有的构造方法默认都会访问父类中的无参的构造方法
因为子类会继承父类中的数据,可能还会使用父类的数据。所以子类初始化之前,一定要先完成父类数据的初始化
每一个子类构造方法的第一条语句默认都是: super()
方法重写
定义相同名字相同参数的方法 以达到子类重写父类方法
@名字 注解
@Override 检测重写的方法是否存在(是否是父类方法)
包
其实就是文件夹,用于对类进行分类管理
包的定义格式
一级名字 (一级文件夹)
com
二级名字 (二级文件夹)
包名
并把class文件存放在 二级文件夹下
Java 创建包了以后,在cmd条件下运行Java程序
1、先把class文件剪切到com下的包名目录下
2、cmd运行以下命令
java com.包名.类名
import
导包 也就是将不同包下的类导入到一个类中
import com.包名.类名
权限修饰符
private 私有的 只能在本类中访问
protected 受保护 只能访同一个包下的类
public 公共的 开放式都能访问
默认的 不同包下的子类与无关类都不能访问
final 最终的
final 可以对方法进行修饰,但是修饰后改方法不再支持重写
final 修饰变量后变量将无法再次赋值
final 修饰类后,该类无法再被继承
final 修饰引用数据类型时数据可以被赋值,但是地址值不在改变
static
static 共享的
被类的所有对象共享
非静态的成员方法
能访问静态的成员变量
能访问非静态的成员变量
能访问静态成员方法
能访问非静态的成员方法
静态的成员方法
能访问静态的成员变量
能访问静态的成员方法
静态成员方法只能访问静态成员
多态
同一个对象,在不同时刻表现出来的不同形态
多态的前提和体现
-
1、有继承/实现关系
-
2、 有方法重写
-
3、有父类引用指向子类对象
多态中成员访问的特点
成员变量:编译看左边,执行看左边
成员方法:编译看左边,执行看右边
多态的好处和弊端
好处
- 提高了程序的扩展性
- 具体体现:定义方法的时候,使用父类型作为参数,将来使用的时候,使用具体的子类型参与操作
- 多态的弊端:不能使用子类特有功能
多态中的转型
-
向上转型(自动)
从子到父
父类引用指向子类对象
-
向下转型(强制转换)
从父到子
父类引用转为子类对象
fu a = new fu(); FU f = (zi)a;注:必须要有一个继承关系
案例: package 转型; import java.util.ArrayList; public class Demo { public static void main(String[] args) { // ArrayList<carMountings> car = new ArrayList<carMountings>(); carMountings fu = new Wheel(); fu.show(); // fu.turn(); // 找不到符号 // 符号: 方法 turn() // 位置: 类型为转型.carMountings的变量 fu fu.show1(); /* * 向上转型 * carMountings fu = new Wheel(); * 子类重写了父类的方法 * 但未重写的父类方法 * 都可直接调用 * * 子类中为重写父类方法其独有方法不可调用 * * 通过子类实例化父类去使用。这种转换其实属于自动转换。 * 当父对象需要用到子对象的某些功能的时候,我们就可以采取向下转型 * */ // 向下转型 Wheel zi = (Wheel) fu; zi.turn(); zi.show(); zi.show1(); } /* *通过父类对象(大范围)实例化子类对象(小范围),这种属于强制转换 * 向下转型可以调用子类的特定功能。 * * */ //总结(有待加深) /* * 向上转型 转型后可以调用子类重写了父类后的方法也可以调用父类方法 * 子类被转换为父类的称为向上转型(自动转换) * * 向下转型 转型后可以通过父类调用子类的特有方法也可以调用子类重写的父类方法,也可以掉用父类方法 * 父类被强制转换为子类称为向下转型(强制转换) * */ }抽象类
在Java中一个没有方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类
抽象类不能直接实例化
应该使用多态的形式
抽象类的关键字 abstract 定义抽象类 public abstract class { // 定义抽象方法 public abstract void name(); }
接口
接口是一种公共的规范标准,只要符合规范标准,大家都可以通用
Java中的接口更多的体现在对行为的抽象
关键字 : interface
类与接口不能有继承关系
要用 implements。关键字修饰
接口也是抽象类
案例
/*
父类
*/
public interface Car {
public abstract void run();
}
/*
子类
*/
public class BC implements Car{
public void run(){
System.out.println("hello word");
}
}
/*
程序入口
*/
public class Demo {
public static void main(String[] args) {
Car car = new BC();
car.run();
}
}
接口中成员特点
成员变量默认都是静态修饰的常量。 可以通过接口直接访问
接口中不能有构造方法
接口中的成员方法不能有非抽象方法
一个类如果没有子类,那么它默认继承Object类
类与接口的关系
实现关系,可以单实现,也可以多实现,还可以继承一个类的同时实现多个接口
public class BC extends Object implements inter,inter1,inter2.....{
}
接口与接口
继承关系,可以是单继承,也可以是多继承
public interface Car extends inter1,inter2,inter3.....{
}
抽象类型作为形参与返回值
方法形参是抽象类名,其实需要的是该抽象类的子类对象
内部类
就是在一个类中定义一个类 。 举例: 类a中定义一个b类,b类就是a类的内部类
语法
public class 类名{
修饰符 class 类名{
}
}
例如:
public class name{
public class name1{
}
}
访问特点
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要想访问内部类,必须创建对象
分为
-
成员内部类
public class name{ public class name1{ } } 类的实例化 外部类.内部类 对象名 = new 外部类().new 内部类(); 私有类中 在外部类总定义方法,实例化内部类 -
局部内部类
public class name{ public void method(){ class name1{ public show (){ sout ("hello wrod"); } } } } 类的实例化 public void method(){ int num = 20; class name1{ public show (){ sout ("hello wrod"); sout (mum); } } name1 n1 = new name1; n1.show();匿名内部类(局部内部类的一种特殊格式)
前提 存在一个类或者接口,这里的类是可以具体类也可以是抽象类
new 类名或者接口名(){
重写方法;
};
范例
new iner(){
public void show(){
}
};
本质:是一个继承了该类或者实现了该接口的子类匿名对象
调用:
new iner(){
public void show(){
}
}.show();// 单次调用
//多次调用
iner i = new iner(){
public void show(){
}
};
i.show();
案例
public interface Car {
void run();
}
public class CarOP {
public void test (Car car){
car.run();
}
}
public class Demo {
public static void main(String[] args) {
CarOP c = new CarOP();
c.test(new Car() {
@Override
public void run() {
System.out.println("汽车正在狂奔");
}
});
}
}
Math
数学运算类
System类
arrays
toString() 返回数组的内容以字符串形式表现
sort() 按数字排序
基本包装类
查看int的范围
Integer.MAX_VALUE 最大值
Integer.MIX_VALUE 最小值
integer
valueOf(); 返回表示指定的int值
int 与 string 之间的相互转换
int ----》 string
int number = 100;
方法一 String s1 = ""+number;
方法二 String.valueOf(number)
String ---- 》 int
String s = "100";
Integer i = Integer.valueOf(s)
int x = i.intValue();
方式二
int y = Integer.parseInt(s)
string 字符串分割
split(“分隔符”)
装箱与拆箱
装箱把基本数据类型转换为对应的包装类型
Integer i = Integer.valueOf(100)
Integer ii = 100; //主动装箱
拆箱
把包装类类型转换为基本数据类型
ii.intValue() ;
只要是对象类型中必须进行部位null的判断
日期类
Date类
分配一个Date 对象,并初始化,以便它代表它分配的时间,精确到毫秒
Date date = new Date();
/*
date.getTime()
获取的日期对象从1970年-1-1 00:00:00 到现在的毫秒值
dade.setTime()
设置时间,给的是毫秒值
*/
SimpleDateFormat类
SimpleDateFormat类是一个具体的类,用于区域设置敏感的方式格式化和解析日期
- y. 年
- M 月
- d。 日
- H。 时
- m。 分
- s 秒
格式化 : 将日期格式化成 日期/时间 字符
format(Date date)
解析 从给定字符串的开始解析文本以生成日期
parse(String source)
Calendar类
异常
异常就是程序出现了不正常的情况
异常体系
-
Throwable
-
error
-
exception
- RuntimeException
- 非RuntimeException
-
error: 严重问题,不需要处理
exception :称为异常类,它表示程序本身可以处理的问题
RuntimeException:在编译期就必须处理,出现问题后,需要我们回来修改代码
非RuntimeException : 编译期就必须处理,否则程序不能通过编译,就更不能正常运行了
JVM的默认处理方案
输出异常信息
停止程序
异常处理
Throwable 的成员方法
getMessage() 返回throwable 的详细消息字符串
toString() 返回此可抛出的简短描述
printStackTrace() 把异常的错误信息输出在控制台
异常处理方案
方案一
try{}catch(){}
方案二
throws 异常类名;
自定义异常
格式:
public class 异常类名 extends Exception {
无参构造
带参构造
}
范例 :
public class ScoreException extends Exception{
public ScoreException () {}
public ScoreException(String message){
super(message);
}
}
编译时异常与运行时异常
编译时异常: 必须显示处理,否则程序就会发生错误,无法通过编译
运行时异常: 无需显示处理,也可以和编译时异常一样处理
throws 与 throw的区别
thorws:
- 用在方法声明后面,跟的是异常类名
- 表示抛出异常,由该方法的调用者处理
- 表示出现异常的一种可能性,不一定会发生这些异常
throw:
- 用在方法体内,跟的是异常对象名
- 表抛出,由方法体内的语句处理
- 执行throw一定抛出了某种异常
集合体系结构
集合
-
单列集合
- list可重复
- arraytlist
- LinkedList
- set不能重复
- HashSet
- TreeSet
- list可重复
-
双列集合
* HashMap
Collection
Collection :
- 是单列集合的顶层接口,它表示一组对象,这些对象也称为collection元素
- jdk不提供此接口的任何直接实现,它可以提供具体的字接口(set和list)实现
创建collection集合的对象
- 多态的方式
- 具体的实现类ArrayList
collection集合常用方法
使用方法:
Collection<数据类型> c = new ArrayList<数据类型>();
|方法名|声明|
|add|添加元素|
|remove|从集合中删除指定元素|
|clear|清空集合中的元素|
|contains|判断集合中是否纯在指定的元素|
|isEmpty|判断集合是否为空|
|size|集合长度|
collection 集合的遍历
// iterator<e 与集合中的泛型
一样>() 返回此集合中元素的迭代器
/*
常用方法
next()迭代返回下一个元素
hasNext()如果迭代具有更多元素 返会 true
*/
//循环遍历
Iterator<String> it = c.iterator<String>;
while(it.hasNext()){
String s = it.Next();
sout(s)
}
list
list:
- 有序集合,用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素并搜索列表中的元素
- 与set集合不同,列表通常允许重复的元素
list特点:
- 有序
- 可重复
迭代器遍历
List<String> c = new ArrayList<String>();
Iterator<String> it = c.iterator<String>;
while(it.hasNext()){
String s = it.Next();
sout(s)
}
List的特有方法
add(int index , e)
Remove(index)
set(index. e)
Get(index)
列表迭代器
是通过list集合的istlterator()方法得到的
常用方法
next()
hashNext()
previous() 返回列表的上一个元素
while(it.hasPrevious()){
it.previous()
}
hasPrevious() 如果此列表迭代器在相反方向遍历时列表具有更多元素,返回true
add() 将指定元素插入列表
增强for循环
简化数组与Collection集合的遍历
for(元素数据类型变量名 : 数组或Collection集合){
//这里使用变量,变量为元素
}
数据结构
常见数据结构----栈
栈:一端开口,一端闭口
数据进入栈模型的过程称为:压/进栈
数据离开模型的过程称为:弹/出栈
栈是一种先进后出的一种数据模型
队列:两端都有开口的
数据从后端进入列队模型的过程称为:入队列
数据从前端离开队列模型的过程称为:出队列
队列是一种数据先进先出的模型
常见的数据结构
数组
特点:
查询数据通过索引定位,查询任意数据耗时相同,查询速度快
删除数据时,要将原始数据删除,同时后面每个数据迁移,删除效率低
添加数据时,添加位置后的每个数据后移,再添加元素,添加效率低
链表
链表的每个元素被称为结点
结点由 结点存储位置 存储具体的数据 下一个结点的位置
结构: | head|^| ^表示指向空地址,结点结束
| head | 11 | A | 37 | C | 96 | D | ^ |
|---|---|---|---|---|---|---|---|
| 头部 | 地址(结点位置) | 数据 | 地址 | 数据 | 地址 | 数据 | 结束 |
特点:
链表是一种查询慢的模型
链表是一种增删快的模型
LIst集合子类特点
list集合常用子类:ArrayList,LinkedList
ArrayList
底层是数组
linked list
底层是链表
linked list集合的特有功能
| 方法名 | 说明 |
|---|---|
| add(e) | 在列表开头插入数据 |
| addLast(e) | 在列表尾部插入数据 |
| getFirst | 返回列表第一个 |
| getLast() | 返回泪飙最后一个 |
| removeFirst() | 从列表删除并返回第一个元素 |
| removeLast | 从列表删除并返回最后一个元素 |
set集合
set集合特点
- 不包含重复元素的集合
- 没有带索引的方法,所以不能使用普通for循环遍历
//定义集合
Set<String> set = new HashSet<String>();
set.add();
哈希值
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的整数
object类中有一个方法可以获取对象的哈希值
hashCode(): 返回对象的哈希码值
对象的哈希值特点
- 同一个对象多次调用hashCode()方法返回的哈希值是相同的
- 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现不同对象的哈希值相同
hashSet
hashSet集合特点
- 底层数据结构是哈希表
- 对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是Set集合,所以不包含重复元素的集合
hashSet集合遍历
//对象
HashSet<String> hs = new HashSet<String>();
add();//添加元素
for(String s : hs){
sout(s);
}
常见的数据结构之哈希表
底层采用数组+链表实现,可以说是一个元素为链表的数组
数据的排列方式由,数据的hash值 对16取余后 等于多少位置就在多少
在存储时位置已有元素会进行hash值的对比 一样后会进行数据是否相同对比不一样则存储
linkdHashSet集合
特点:
- 哈希表和链表实现的Set接口,具有可预测的迭代次序
- 有链表保证元素有序,也就是是元素的存储和取出顺序是一致的
- 有哈希表保证元素唯一,也就是说没有重复的元素
linkdHashSet<String> linkdHashSet = new linkdHashSet<String>();
TreeSet集合
特点:
- 元素有序,这里的顺序不是指存储和取出的顺序,而是按一定的规则进行排序,具有排序方式取决与构造方法
- 没有带索引的方法,所以不能使用普通for循环遍历
- 由于是set集合,所以不包含重复元素
TreeSet<Integer> ts = new TreeSet<Integer>();
自然排序Comparrable的使用
public calss student implements Comparable<Student>{
//在使用comparable<E>时需要重写
public int compareTo(Student s){
/*
返回值:
0 代表返回1一个
1 代表按照插入顺序全部返回
-1 代表按照插入的顺序反向全部返回
*/
return 1;
}
}
按年龄排序
public int compareTo(Student s){
int num = this.age - s.age;
int num = s.age - this.age;
return num;
int num2 = num == 0?this.name.compareTo(s.name):num;
return num2;
}
泛型
他提供了编译时类型安全检测机制,该机制允许在编译时检测到非法类型它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数
泛型的定义格式:
-
<类型>:指定一种类型的格式.
-
<类型1,类型2>指定多种类型的格式,多种类型之间用逗号隔开。
-
将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
Collection c = new ArrayList();
c.add("hello");
c.add("world");
Iterator it = c.iterator();
while(it.hasNext()){
Object obj = it.next();
sout(obj);
}
好处:
- 把运行时期的问题提前到编译期、
- 避免了强制类型转换
泛型类
定义格式:
class name <Type>{}
//泛型类
public class Car<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
泛型方法
//定义方法
public <Type> returnType name(){
}
范例:
public <T> void show(T t){
sout(t);
}
泛型接口
//定义方法
修饰符 interface 接口名 <类型>{}
范例:
public interface show <T> {
}
类型通配符
为了表示各种泛型List的父类
- 类型通配符:<?>
- list<?> : 表示元素类型未知的list,它的元素可以匹配任何的类型
- 这种带通配符的List仅表示它是各种泛型list的父类,并不能把元素添加到其中
如果说我们不希望List<?>是任何泛型list的父类,只希望它代表某一类泛型list的父类,可以使用类型通配符的上限
- 类型通配符上限:<? extends 类型>
- list<? extends Number>: 它表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,我们也可以指定通配符的下限
- 类型通配符下限: <? super 类型>
- list<? super Number>: 它表示的类型是Number或者其父类型
可变参数
可变参数又称参数个参数可变,用作方法的形参方式出现,那么方法参数个数就是可变的
范例:
public static int sum(int...a){}
求总和
public static int sum(int...a){
int sum = 0;
for(int i : a ){
sum += i;
}
return sum;
}
可变参数的使用
Arrays工具类有一个静态方法:
public static <T> List<T> asList(T...a);返回指定数组支持的固定大小的列表
返回的集合不能做增删操作,可以做修改操作
List接口中有一个静态方法:
public static <e> list<e>of(e...elements); 返回包含任意数量元素的不可变列表
返回的集合不能做增删改操作
Set接口中有一个静态方法:
public static <e> Set <e> of(e...elements);返回一个包含任意数量元素的不可变集合
在给元素的时候,不能给重复的元素
返回的集合不能做增删操作,没有修改操作
Map集合
-
interface Map<K,V> K:键的类型 V:值的类型
-
将建映射到值的对象;不能包含重复的键,每一个键可以映射多个值
-
实现类 HashMap
Map<String,String> map = new HashMao<String,String>(); map.put("key","value"); // 当键重复时,后添加的值会把原来的值替换掉
| 方法名 | 说明 |
|---|---|
| put | 添加元素 |
| remove | 根据键删除值对元素 |
| clear | 移除所有的键值对元素 |
| containsKey | 判断集合是否包含指定的键 |
| containsValue | 判断集合是否包含指定的值 |
| isEmpty() | 判断集合是否为空 |
| size | 集合长度,也就是集合中键值对的个数 |
| get | 根据键获取值 |
| Set KeySet() | 获取所有键的集合 |
| Collection values() | 获取所有值的集合 |
| Set<Map.Entry<K,V>>entrySet() | 获取所有键值对对象的集合 |
Map集合的遍历
/* 方式一:
思路
把所有键都集中起来
遍历键,获取每一个键
更具键找对应值
*/
Map<String,String> map = new HashMap<String,String>();
map.put("1001","huahua");
map.put("1002","goushihua");
map.put("1003","goushihua");
for(String a : map.keySet() ){
System.out.println(map.get(a));
}
/*
方式二:
获取所有键值对对象的集合
*/
Map<String,String> map = new HashMap<String,String>();
map.put("1001","huahua");
map.put("1002","goushihua");
map.put("1003","goushihua");
Set<Map.Entry<String,String>> en = map.entrySet();
for(Map.Entry<String,String> me : en){
System.out.println(me.getKey());
System.out.println(me.getValue());
System.out.println(me);
}
I/O流
File
它是文件和目录路径名的抽象表示
- 文件和目录是可以通过File封装成对象的
- 对于File而言,其实封装的并不是一个真正存在的文件,仅仅是一个路径名而已。
构造方法:
| 方法名 | 说明 |
|---|---|
| File(String) | 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例 |
| File(String,String) | 从父路径名字字符串和子路径字符串创建新的File实例 |
| File(File,String) | 从父抽象路径名和子路径字符串创建新的File实例 |
File f = new File("H:\\java_study\\java.txt");
File文件的创建
| 方法名 | 说明 |
|---|---|
| createNewFile() | 当具有该名称的文件加不存在时,创建一个由该抽象路径命名的新文件 |
| mkdir() | 创建由此抽象路径命名的目录 |
| mkdirs() | 创建由此抽象路径名命名的目录,包括任何必需但不存在的父目录 |
package File;
import jdk.swing.interop.SwingInterOpUtils;
import java.io.File;
public class Demo1 {
public static void main(String[] args) {
// File file = new File("H:\\java_study\\java.txt");
/*
|isDirectory|判断抽象路径是否为目录|
*/
// System.out.println(file.isDirectory());
/*
|isFile|判断抽路径是否为文件|
*/
// System.out.println(file.isFile());
/*
|exists|判断抽象路径名中的文件是否存在|
*/
// System.out.println(file.exists());
/*
|getAbsolutePath|返回抽象路径的绝对路径名|
*/
// System.out.println(file.getAbsolutePath());
/*
|getPath|返回抽象路径转换后的字符串名字|
*/
// System.out.println(file.getPath());
/*
|getName|返回抽象路径名表示的文件或目录的名称|
*/
// System.out.println(file.getName());
/*
|list|返回抽象路径名表示的目录中的文件和目录的名称字符串数组|
|listFile|返回此抽象路径名表示的目录中的文件和目录的对象数组|
*/
File f = new File("H:\\java_study");
// System.out.println(f.list()); //Ljava.lang.String;@119d7047
// for(String s : f.list()){
// System.out.println(s);
// }
for(File f1 : f.listFiles() ){
// System.out.println(f1);
if(f1.isFile()){
System.out.println("----------");
System.out.println(f1);
}else{
System.out.println("This not is a File");
}
}
}
}
//删除
package File;
import java.io.File;
public class Demo2 {
public static void main(String[] args) {
File f = new File("H:\\java_study\\java1.txt");
System.out.println(f.delete());
}
}
递归
递归:以编程角度来看,递归指的是方法调用方法本身的现象
递归解决问题的思路
- 把应该复杂问题层层转换为应该与原问题相似的规模较小的问题来求解
- 递归策略只需要少量的程序就可以描述出解题过程所需要的多次重复计算
案例:
//编程求不死神兔问题
int[] arr = new int[20];
arr[0] = 1;
arr[1] = 2;
for (int i = 2;i < arr.length; i++){
arr[i] = arr[i-1] + arr[i-2];
}
sout(arr[19]);
/*
递归解法
*/
public static int f(int n){
if(n = 1 || n = 2){
return 1;
}
else{
return f(n-1)+f(n-2)
}
}
递归解决问题
- 递归出口:否则会出现内存溢出
- 递归规则:与原问题相似的规模较小的问题
递归求阶乘
public class Demo1 {
public static void main(String[] args) {
System.out.println(f(5));
}
public static int f(int n) {
if (n == 1) {
return 1;
} else {
return n * f(n - 1);
}
}
}
递归遍历文件目录
File f = new File("E:\\java");
getAllFile(f);
public static void getAllFile(File f){
File[] file = f.ListFile();
if(file != null){
for(File file : file){
if(file.isDirectory()){
getAllFile(file)
}else{
sout(file.getAbsolutePath() );
}
}
}
}
字节流
I/O流分类:
-
按照数据流向
输入流:读取数据
输出流:写数据
-
按照数据类型来分
字节流
字节输入流:字节输出
字符流
字符输出流:字符输出
一般来说,我们说IO流的分类是按照数据类型来分的
-
如果数据通过Windows自带的记事本软件打开,我们还可以读懂里面的内容,就使用字符流,
否则就使用字节流,如果不知道用那个就使用字节流,字节流又称万能流
字节流写数据
字节流的基类
- InputStream:这个抽象类是表示字节输入流的所有超类
- OutoutStream:这个抽象类是表示字节输出流的所有类的超类
- 子类名特点:子类名称都是以其父类名之为子类名的后缀
FileOutoutStream:文件输出流用于将数据写入File
- FileOutoutStream(String name): 创建文件输入流以指定的名称写入文件
FileOutputStream fos = new FileOutputStream("E:\\java_study");
| 方法名 | 说明 |
|---|---|
| write(int b) | 将指定的字节写入此文件输出流一次写入应该字节数据 |
| write(byte[] b) | 将b.length字节从指定的字节数组写入此文件输出流一次写一个字节数组数据 |
| write(byte[]b,int off, int len) | 将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流一次写一个字节数组的部分数据 |
换行符
- windows :\r\n
- linux: \n
- mac:\r
字节输出流写入数据实现追加写入
FileOutputStream fos = new FileOutputStream("E:\\java_study",true);
字节流写入数据时的异常处理
finally:在异常处理时提供finally块来执行所有清楚操作,比如是IO流中的释放资源
特点:被finally控制的语句块一定会执行,除非JVM退出
使用格式
try{
}catch{
}finally{
}
字节输入流读取文件数据
FileInputStream fis = new FikeInputStream("E:\\java_study");
//调用字节输入流的读数据方法
//int read(),从输入流读取一个字节
int by = fis.read();
sout(by);//97
sout((char)by);//a
//第二次读取数据
int by = fis.read();
sout(by);//98
sout((char)by);//b
//循环读取多个数据
int by = fis.read();
while(by != -1){
sout((char)by);
by = fis.read();
}
//释放资源
fis.close();
案例一 复制文本文件:
/*
案例一:
先读取文件
后写入到目的文件
*/
// 创建文件输出流
FileInputStream fis = new FileInputStream("H:\\java_study\\index.php");
// 创建文件输出流
FileOutputStream fos = new FileOutputStream("H:\\java_study\\login.php");
int by;
// 定义文件结束标志
// read()方法在读取玩数据时返回-1
while ((by=fis.read()) !=-1){
// 把读取的数据写入
fos.write(by);
}
案例二
/*
字节输入流一次读取一个数组数据的方法
// int read(byte[] b): 该输入流读取最多 b.length个字节的数据到一个字节数组中
*/
FileInputStream fis = new FileInputStream("H:\\java_study\\index.php");
/* byte[] b = new byte[5];
// while ()
int len = fileInputStream.read(b);
System.out.println(len);
// String str = new String(b);
String str = new String(b,0,len);
System.out.println(str);
*/
byte[] bys = new byte[1024];
int len;
while ((len = fis.read(bys))!=-1){
System.out.println(new String(bys));
}
fis.close();
案例三
/*
复制图片
*/
FileInputStream fis = new FileInputStream("H:\\flh.jpg");
FileOutputStream fos = new FileOutputStream("H:\\java_study\\flh.jpg");
byte[] byt = new byte[1024];
int by ;
while ((by = fis.read(byt)) != -1){
fos.write(byt,0,by);
// System.out.println(byt);
}
// 输出地址与输入地址不能相等,否则会损坏图片
字节缓冲流
缓冲输出流
BufferOutputStream:该类实现缓存输出流。通过设置这样的输出流应用程序可以想底层输入流写入字节,而不必为写入的每个字节导致底层系统的调用
缓存输入流
BufferInputStream:创建BufferIutputStream将创建一个内部缓冲区数组。当从流中读取或跳过字节时,额你不缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
构造方法
- 字节缓冲输出流:BufferOutputStream(OutputStream out)
- 字节缓冲输入流:BufferInputStream(InputStream in);
为什么构造方法需要字节流而不具体路径
- 字节缓冲流仅仅提供缓冲区,而不是真正的读写数据还得依靠基本的字节流对象进行操作
//BufferOutputStream(OutputStream out)
// 写入数据
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("H:\\java_study\\java.txt"));
bos.write("hello\r\n".getBytes());
bos.write("world\r\n".getBytes());
bos.write("2003".getBytes());
bos.close();
//BufferInputStream
//读取数据
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("H:\\java_study\\java.txt"));
int by ;
byte[] byt = new byte[1024];
while ((by = bis.read(byt)) != -1){
System.out.println(new String(byt));
}
bis.close();
//第二个方式
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("H:\\java_study\\java.txt"));
int bty;
while ((by = bis.read()) != -1){
System.out.println((char)by);
}
bis.close();
案例:复制视频
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis();
// method1(); 一共耗时:157907ms
// method2(); 一共耗时:237ms
// method3(); 一共耗时:1156ms
// method4(); 一共耗时:60ms
long endTime = System.currentTimeMillis();
long runTime = endTime - startTime;
System.out.println("一共耗时:"+runTime+"ms");
}
public static void method1() throws IOException {
FileInputStream fis = new FileInputStream("H:\\like.mp4");
FileOutputStream fos = new FileOutputStream("H:\\java_study\\like.mp4");
int by;
while ((by = fis.read()) != -1){
fos.write(by);
}
}
public static void method2() throws IOException{
FileInputStream fis = new FileInputStream("H:\\like.mp4");
FileOutputStream fos = new FileOutputStream("H:\\java_study\\like.mp4");
int len;
byte[] b =new byte[1024];
while ((len = fis.read(b))!=-1){
fos.write(b,0,len);
}
}
public static void method3() throws IOException{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("H:\\like.mp4"));
BufferedOutputStream bos =new BufferedOutputStream(new FileOutputStream("H:\\java_study\\like.mp4"));
int by;
while ((by = bis.read()) != -1){
bos.write(by);
}
}
public static void method4() throws IOException{
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("H:\\like.mp4"));
BufferedOutputStream bos =new BufferedOutputStream(new FileOutputStream("H:\\java_study\\like.mp4"));
int len;
byte[] bytes =new byte[1024];
while ((len = bis.read(bytes)) != -1){
bos.write(bytes,0,len);
}
}
}
字符流
由于字节流操作中文不是特别方便,所以Java提供了字符流
- 字符流 = 字节流 + 编码表
用字节流复制文本文件时,文本文件也会有中文,原因是最终底层操作会自动进行字节拼接成中文
- 如何识别中文
- 汉字存储的时候,无论选择哪种编码存储,第一个字节都是负数
编码表
基础知识
- 计算机中存储的信息都是二进制数表示的;
- 按照某种规则,将字符存储到计算机中,称为编码。反之,将存储在计算机中的二进制按照某种规则解析出来,称为解码。注: 按照某种规则存储,必须按照这种规则解析,否则会导致乱码。
字符集:
-
是一个系统支持的所有字符的集合,包括各国家文字,标点符号,图形符号,数字等
-
计算机要准确的存储和识别各种字符集符号,就需要进行字符编码,一套字符集必然至少有一套字符编码。
常见字符集有ASSII字符集,GBXXX字符集,Unicode字符集
- ASCII 是基于拉丁字母的一套电脑编码系统,用于显示现代英语,主要包括控制字符(回车,退格,换行)和可显示字符(英文字符大小写,阿拉伯数字和西文符号)
- 基本的ASSCII字符集,使用7位表示一个字符,共128字符。ASSCII的扩展字符集使用8位表示一个字符,共256字符,方便支持欧洲常用字符。是一个系统支持的所有字符集合,包括国家文字,标点符号,图形符号,数字等
GBxxx字符集:
- GB2312:简体中文码表,一个小于127的字符的意义与原来相同,单两个大于127的字符连在一起时,就表示一个汉字,这样大约可以组合了包含7000多个简体汉字,此外数学符号,罗马希腊字母,日文的假名等都编进去了。连在ASSCII里原本就有的数字,标点,字母都统统重新编了两个字节长的编码,这就是常说的“全角”字符,而原来在127号以下的叫“半角”字符
-
GBK:最常用的中文编码表。是在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录21003汉字,完全兼容GB2312标准,同时支持繁体汉字以及日韩字等
-
GB18030: 最新的中文编码表。收录汉字70244个,采用多字节编码,每个字可以由1个、2个或4个字节组成。支持中国国内少数民族的文字,同时支持繁体汉字以及日韩文字等
Unicode字符集:
-
为表示任意语言的任意字符而设计,是业界的一种标准,也称为统一码、标准万国码。它最多使用4个字节的数字来表示每个字母、符号、或者文字。有三种编码方案,UTF-8UTF16 and UTF32。最常用的UTF-8编码。
-
UTF-8编码:可以用来表示Unicode标准中任意字符,它是电子邮件、网页及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组(IETF)要求所有互联网协议都必须支持utf-8编码。它使用一至四个字节为每个字符编码
编码规则:
- 128个US-ASCII字符,只需一个字节编码
- 拉丁文等字符,需要两个字节编码
- 大部分常用字(中文),使用三个字节编码
- 其他极少使用的Unicode辅助字符·1,使用四字节编码
字符中的编码解码问题
编码:
- byte[] getBytes():使用平台默认字符集将该String编码为一系列字节,将结果存储到新的字节数组中
- byte[] getBytes(String charSetName):使用指定的字符集将该String编码为一系列字节,将结果存储到新的字节数组中
解码:
- String(byte[] BYTES):通过使用平台的默认字符集解码指定的字节数组来构造新的String
- String(byte[] BYTES,String charSetName):通过使用指定的字符集解码指定的字节数组来构造新的String
/*
编码与解码
*/
/*
* 编码与解码
* */
// 默认字符
// 编码
// String s = "狗屎花";
// byte[] bys = s.getBytes();
// System.out.println(Arrays.toString(bys));
//
// //解码
// String b = new String(bys);
// System.out.println(b);
String s = "哈啥给";
byte[] bys = s.getBytes("UTF-8");
System.out.println(Arrays.toString(bys));
System.out.println(new String(bys,"UTF-8"));
字符流中的编码解码问题
字符流抽象基类
- Reader:字符输入流的抽象类
- Writer:字符输出流的抽象类
字符流中和编码解码问题相关的两个类:
- InputStreamReader
- OutputStreamWriter
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("H:\\java_study\\java.txt"),"UTF-8");
osw.write("你好");
osw.close();
InputStreamReader isr = new InputStreamReader(new FileInputStream("H:\\java_study\\java.txt"),"UTF-8");
int by;
while ((by = isr.read()) != -1){
System.out.print((char)by);
}
isr.close();
字符流写数据的方法
| 方法名 | 说明 |
|---|---|
| write(int) | 写入一个字符 |
| write(char[] cbuf) | 写入一个字符数组 |
| write(char[] ,int off ,int len) | 写入字符数组的一部分 |
| write(String str) | 写入一个字符串 |
| write(String,int off,int len) | 写入一个字符串的一部分 |
案例:
// OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("H:\\java_study\\java.txt"));
InputStreamReader isr = new InputStreamReader(new FileInputStream("H:\\java_study\\java.txt"));
/*osw.write(98);
osw.flush();
// osw.close();
*/
String s = "hello";
char[] ch = new char[1024];
int len;
while((len = isr.read(ch)) != -1) {
System.out.println(new String(ch,0,len));
}
Filewrite
FileRead
FileReader fr = new FileReader("H:\\JAVA_STUDY\\index.java");
FileWrite fw = new FileWrite("H:\\java\\index.jsp");
字符缓冲流
- BuffredWriter:将文本写入,缓存字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小、或者可以接受默认大小。
- BufferedReader: 从字符输入流读取文本,缓存字符,以提供字符数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。
构造方法
-
BuffereWriter(Writer out)
-
BufferedReader(Reader in)
案例
BufferedWriter bw = new BufferedWriter(new FileWriter("H:\\java_study\\java.txt"));
bw.write("hello\n\r");
bw.write("word\n\r");
bw.write("java\n\r");
bw.close();
BufferedReader br = new BufferedReader(new FileReader("H:\\java_study\\java.txt"));
int by ;
char[] ch = new char[1024];
while ((by = br.read(ch)) != -1 ){
System.out.println(new String(ch,0,by));
}
br.close();
字符缓冲流的特有功能
BuffereWriter:
newLine():写一行行分隔符,行分隔符字符串又系统定义
BufferedReader
readLine:()读一行文字,结果包含行的内容的字符串,不包括任何终止字符,如果流的结尾已经到达,则为null(只读内容不读换行符号)
BufferedWriter bw = new BufferedWriter(new FileWriter("H:\\java_study\\java.txt"));
BufferedReader br = new BufferedReader(new FileReader("H:\\java_study\\java.txt"));
for (int i = 0; i < 10; i++) {
bw.write("hello" + i);
bw.newLine();
bw.flush();
}
for (int i = 0;i <= 10;i++ ) {
System.out.println(br.readLine());
}
案例:集合到文件
/*
需求把ArrayList集合中的字符数据写入到文本文件,要求:一个字符串元素为一行
*/
ArrayList<String> array = new ArrayList<String>();
BufferedWriter bw = new BufferedWriter(new FileWriter("H:\\java_study\\java.txt"));
array.add("hello");
array.add("world");
array.add("java");
for(String i : array){
bw.write(i);
bw.newLine();
bw.flush();
}
bw.close();
案例:文件到集合
ArrayList<String> arrayList = new ArrayList<>();
BufferedReader br = new BufferedReader(new FileReader("H:\\java_study\\java.txt"));
String len;
while ((len = br.readLine()) != null){
arrayList.add(len);
}
for (String i: arrayList) {
System.out.println(i);
}
案例:复制单级文件夹
package 案例;
import java.io.*;
public class FirstFileCopy {
public static void main(String[] args) throws IOException {
File srcFolder = new File("D:\\java_study\\javaJDK");
//申明文件源路径对象
String srcFolderName = srcFolder.getName();
// 获取文件源路径名字
File destination = new File("D:\\java_study\\javaSE");
//申明目的文件源对象
if (!destination.exists()){
destination.mkdir();
}
//判断目的文件是否存在,不存在则创建
File[] files = srcFolder.listFiles();
//读取文件源内的文件列表
System.out.println(files);
for(File FileName : files){
String fileName = FileName.getName();
File destFile = new File(destination,fileName); //从父抽象路径名和子路径名字符串创建新的 File实例。
copyFile(FileName,destFile);
// System.out.println(FileName);
}
}
public static void copyFile(File srcName,File destFile) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcName));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1){
bos.write(bytes,0,len);
}
bis.close();
bos.close();
}
}
案例:复制多级文件夹
package 案例;
import java.io.*;
public class Copy {
public static void main(String[] args) throws IOException {
File srcFile = new File("D:\\java_study\\javaJDK");
File destFile = new File("F:\\");
isFolder(srcFile,destFile);
}
public static void isFolder(File srcFile,File destFile) throws IOException{
if(srcFile.isDirectory()){
String srcFileName = srcFile.getName();
File newFolder = new File(destFile,srcFileName);
if(!newFolder.exists()){
newFolder.mkdir();
}
File[] listFiles = srcFile.listFiles();
for(File f : listFiles){
isFolder(f,newFolder);
}
}else {
File newFile = new File(destFile,srcFile.getName());
copyFile(srcFile,newFile);
}
}
public static void copyFile(File srcName, File destFile) throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcName));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFile));
byte[] bytes = new byte[1024];
int len;
while ((len = bis.read(bytes)) != -1){
bos.write(bytes,0,len);
}
bis.close();
bos.close();
}
}
特殊操作流
标准输入流
System类中有两个静态的成员变量:
-
InputStream in:标准输入流。通常该流对应键盘输入或由主机环境或用户指定的另一个输入源
public static void main(String[] args) throws IOException { InputStream is = System.in; // int len; // while ((len = is.read()) != -1){ // System.out.println((char)len); // } /* * 字节流转换为字符流 * BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); * * 转换后 * 可以输入字符串且字符串一次读取一行 * */ BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("请输入一个字符串"); String s = br.readLine(); System.out.println(s); System.out.println("请输入一个整数"); int num = Integer.parseInt(br.readLine()); System.out.println(num); //以上实现了键盘输入 /* * 以上虽然实现了键盘输入 * 但是太过于繁琐 * 所以 * java提供了 * Scanner类 * */ Scanner sc = new Scanner(System.in); -
PrintsStream out: 标准输出流。通常该流对应于显示输出或由主机环境或用户指定的另一个输出目标
PrintStream ps = new PrintStream("D:\\java_study\\java.txt"); //字节输出流的方法它(ps)都有 ps.write(97); ps.print(97); ps.println(); ps.print(98); ps.close(); PrintStream ps = new PrintStream(System.out); ps.println("hello"); ps.print(100); /* * System.out 它的本质就是一个字节输出流 * PrintStream 下的方法System.out都可以用 * */
打印流
-
字节打印流:PrintStream
- PrintStream(String fileName):使用指定文件名创建新的打印流
- 使用继承父类的方法写数据,查看的时候会转码;使用自己特有的方法写数据,查看的数据原样输出
-
字符打印流:PrintWriter
-
字符流
public static void main(String[] args) throws IOException { // PrintWriter pw = new PrintWriter("D:\\java_study\\java.txt"); // pw.write("hello\r\nword"); // pw.println("hello word"); // pw.flush() PrintWriter pw = new PrintWriter(new FileWriter("D:\\java_study\\\\java.txt"),true); pw.println("hello"); /* * 不用刷新 * new PrintWriter(FileWriter pw,boolean autoFlush); * */ pw.close(); }
-
打印流的特点:
-
只负责输出数据,不负责读取数据
-
有自己特有的方法
案例:
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("D:\\java_study\\java.txt"));
PrintWriter pr = new PrintWriter(new FileWriter("D:\\java_study\\javaJDK\\index.java"));
String line;
while ((line = br.readLine()) != null){
pr.println(line);
}
}
对象序列化流
对象序列化流:就是将对象保存在磁盘中,或者网络中传输对象
这种机制就是使用一个字节序列表示一个对象,该序列包含:对象类型,对象数据和对象中存储的属性等信息
字节序列化写到文件之后,相当于文件中持久保存了一个对象信息
反之、该字节序列还可以从文件中读取出来,重构对象,对它进行反序列化
对象序列化流和对象反序列化流:
- 对象序列化流:ObjectOutputStream
- 对象反序列化流:ObjectInputStream
对象序列化流:ObjectOutputStream:
- 将Java对象的原始数据类型和图形写入OutputStream。可以使用ObjectInputStream读取(重构)对象。可以通过使用流的文件来实现对象的持久存储。如果流是网络套接字流,则可以在另一个主机或另一个进程中重构对象
- 构造方法
- ObjectOutputStream(OutputStream out):创建一个写入指定的OutputStream 的ObjectOutputStream
- 序列化对象的方法
- viod writeObject(Object obj):将指定的对象写入ObjectOutputStream
public static void main(String[] args) throws IOException {
ObjectOutputStream oos =new ObjectOutputStream(new FileOutputStream("D:\\java_study\\Student.txt"));
Student s1 = new Student("zhangsan",25);
// oos.writeObject(s1);
// oos.close();
// NotSerializableException 当实例需要具有Serializable接口时抛出。 序列化运行时或实例的类可以抛出此异常。 参数应该是类的名称。
// 在对类进行序列化时 必须实现java.io.Serializable接口。
oos.writeObject(s1);
oos.close();
}
// Serializable 是一个标记接口,实现该接口,不需要重写任何方法
反序列流:
ObjectInputStream:
-
ObjectInputStream反序列化优先使用ObjectOutStream编写的原始数据和对象
-
构造方法:
-
ObjectInputStream(InputStream in): 创建从指定的InputStream读取的ObjectInputStream
-
反序列化方法:
- Object readObject():从ObjectInputStream读取一个对象
-
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\java_study\\Student.txt"));
Object s = ois.readObject();
Student student = (Student)s;
/*
* 向下转型
* 所有的类都是Object的子类
* */
System.out.println(student.getName()+","+student.getAge());
}
用对象序列化流序列化一个对象后,假如我们修改了对象所属的类文件,读取数据会不会出问题呢?
- 会,会抛出InvalidClassException异常
任何解决
-
给所属类加一个serialVersionUID
格式:private static final long serialVersionUID
某个成员变量不想被序列化如何实现
- 给该成员变量加transient
Properties
- 是一个Map体系的集合类
- Properties可以保存到流中或者从流中加载
Properties 作为Map集合的特有方法
| 方法名 | 说明 |
|---|---|
| setProperty | 设置集合的键和值,都是String类型,底层调用Hashtable方法 |
| getProperty | 使用此属性列表中指定的键搜索属性 |
| Set stringPopertyName() | 从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串 |
public static void main(String[] args) {
Properties prop = new Properties();
prop.setProperty("10001","zhangsna");
prop.setProperty("10002","lishi");
prop.setProperty("10003","wangwu");
//setProperty设置集合的键和值,都是String类型,底层调用Hashtable方法
//getProperty使用此属性列表中指定的键搜索属性
//System.out.println(prop.getProperty("10001"));
// Set<String> stringPopertyName()从该属性列表中返回一个不可修改的键集,其中键及其对应的值是字符串
Set<String> StudentKey = prop.stringPropertyNames();
for(String key : StudentKey){
// System.out.println(key);
String name = prop.getProperty(key);
System.out.println(name + "," + key);
}
Properties 与IO流结合的方法
| 方法名 | 说明 |
|---|---|
| load(InputStream in) | 从输入字节流读取属性列表(键和元素对) |
| load(Reader reader) | 从输入字符流读取属性列表(键和元素对) |
| store(OutputStream out,String comments) | 将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流 |
| store(Writer writer,String comments) | 将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(Reader)方法的格式写入输出字符流 |
package 对象序列化流;
import java.io.*;
import java.util.Properties;
public class PropertiesDemo2 {
public static void main(String[] args) throws IOException{
//Properties 中IO流的特有方法
/*
| load(InputStream in) | 从输入字节流读取属性列表(键和元素对) |
| ----------------------------------------- | ------------------------------------------------------------ |
| load(Reader reader) | 从输入字符流读取属性列表(键和元素对) |
| store(OutputStream out,String comments) | 将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(InputStream)方法的格式写入输出字节流 |
| store(Writer writer,String comments) | 将此属性列表(键和元素对)写入此Properties表中,以适合于使用load(Reader)方法的格式写入输出字符流 |
*/
//store(Writer writer,String comments)
//将集合中的数据写入到文件
// PropertiesToFile();
// load(Reader reader)
// 将文件中的数据写入到集合中
//FileToPoperties();
//load(InputStream in) | 从输入字节流读取属性列表(键和元素对)
// InputStreamToProperties();
//store(OutputStream out,String comments)
OutputStreamToProperites();
}
private static void OutputStreamToProperites() throws IOException {
FileOutputStream fos = new FileOutputStream("D:\\java_study\\java.txt");
Properties prop = new Properties();
prop.setProperty("10001","zhangsna");
prop.setProperty("10002","lishi");
prop.setProperty("10003","wangwu");
prop.setProperty("10004","jiji");
prop.store(fos,"hello");
}
private static void InputStreamToProperties() throws IOException{
FileInputStream fis = new FileInputStream("D:\\java_study\\java.txt");
Properties prop = new Properties();
prop.load(fis);
System.out.println(prop);
}
private static void FileToPoperties() throws IOException{
FileReader fr = new FileReader("D:\\java_study\\java.txt");
Properties prop = new Properties();
prop.load(fr);
System.out.println(prop);
}
private static void PropertiesToFile() throws IOException {
FileWriter wr = new FileWriter("D:\\java_study\\java.txt");
Properties prop = new Properties();
prop.setProperty("10001","zhangsna");
prop.setProperty("10002","lishi");
prop.setProperty("10003","wangwu");
prop.store(wr,null);
}
}
多线程
实现多线程
进程:是正在运行的程序
- 是系统进行资源分配和调用的独立单位
- 每一个进程都有它自己的内存控件和系统资源
线程:是进程中的单个顺序控制流,是一条执行路径
- 单线程:一个进程如果有一条执行路径,则称为单线程程序
- 多线程:一个进程如果有多条执行路径,则称为多线程程序
多线程的实现方式
Thread类:是一个线程类,Java虚拟机允许应用程序同时执行多个执行线程
方式1:继承Thread类
- 定义一个类MyThread继承Thread类
- 在MyThread类中重run()方法
- 创建MyThread类的对象
- 启动线程
注意:
- 为什么要重写run()方法?
- 因为run()方法是用来封装被线程执行的代码
- run()方法和start()有何区别?
- run():封装线程执行的代码,直接调用,相当于普通方法的调用
- start():启动线程;然后由jvm调用此线程的run()方法
设置和获取线程名称
Thread类提供了设置和获取线程名称的方法
| 方法名 | 说明 |
|---|---|
| setName(String name) | 将此线程名称改为name |
| getName() | 返回此线程名称 |
my1.setName("线程1");
my2.setName("线程2");
通过带参构造方法设置线程名字
public class MyThread extends Thread{
MyThread(String name){
super(name);
}
@Override
public void run() {
for(int i =0 ;i <= 10;i++){
System.out.println(getName()+":"+i);
}
}
}
//Demo 类
main:
MyThread my1 = new MyThread("线程1");
MyThread my2 = new MyThread("线程2");
在非继承,非实例化 Thread类时查看当前程序的线程名称
System.out.println(Thread.currentThread().getName());
//currentThread() 返回当前正在执行的线程对象
线程调度
线程有两种调度模型
- 分时调度模型:所有线程轮流使用CPU的使用权,平均分配每个线程占用CPU的时间片
- 抢占式调度模型:优先让优先级高的线程使用CPU,如果线程优先级相同,那么会随机选择一个,优先级高的线程获取的Cpu时间片相对多一些
Java使用的是抢占式调度模型
假如计算机只有一个CPU,那么CPU在某一个时刻只能执行一条指令,线程只有得到CPU时间片,也就是使用有权,才可以执行指令。所以说多线程程序的执行是有随机性的,因为谁抢到cpu的使用权是不一定的
Thread类中设置和获取线程优先级的方法
| 方法名 | 说明 |
|---|---|
| setPriority(int newPriority) | 更改此线程的优先级 |
| getPriority() | 获取此线程的优先级 线程优先级最大值10 最小值1 默认值5 |
注:线程优先级高仅仅代代表获取到cpu时间片的几率高,并不代表它永远最先允许
package 多线程;
public class Demo2 {
public static void main(String[] args) {
MyThread my1 = new MyThread("线程1");
MyThread my2 = new MyThread("线程2");
MyThread my3 = new MyThread("线程3");
my1.setPriority(10);
my2.setPriority(1);
my3.setPriority(5);
my1.start();
my2.start();
my3.start();
}
}
线程控制
| 方法名 | 说明 |
|---|---|
| sleep(long millis) | 使当前正在执行的线程停留(暂停执行)指定的毫秒数 |
| join() | 等待这个线程死亡 |
| setDaemon(boolean on) | 将此线程标记为守护线程,当允许的线程都是守护线程时,Java虚拟机将退出 |
线程的生命周期

创建多线程的方式二
- 定义一个类MyRunnable实现Runnable接口
- 在MyRunnable类中重写run()方法
- 创建MyRunnable类的对象
- 创建Thread类的对象,把MyRunnable对象作为构造方法的参数
- 启动线程
package 多线程;
public class MyRunnable implements Runnable{
@Override
public void run() {
for(int i = 0;i<=100;i++){
System.out.println(Thread.currentThread().getName()+"+"+i);
}
}
}
// rRunnableDemo
package 多线程;
public class RunnableDemo1 {
public static void main(String[] args) {
MyRunnable my = new MyRunnable();
// Thread t1 = new Thread(my);
// Thread t2 = new Thread(my);
Thread t1 = new Thread(my,"线程1");
Thread t2 = new Thread(my,"线程2");
t1.start();
t2.start();
}
}

线程同步
案例:买票
package 案例;
public class ticket implements Runnable{
private int ticket = 100;
@Override
public void run() {
while (true) {
if (ticket > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在买票" + ticket + "号");
ticket--;
}else {
System.out.println("今天的票已卖完,请明天再来");
System.exit(0);
}
}
}
}
package 案例;
public class ticketDemo {
public static void main(String[] args) {
ticket tk = new ticket();
Thread t1 = new Thread(tk,"窗口1");
Thread t2 = new Thread(tk,"窗口2");
Thread t3 = new Thread(tk,"窗口3");
t1.start();
t2.start();
t3.start();
}
}
为什么会出现问题?
- 是否多线程环境
- 是否有共享数据
- 是否有多条语句操作共享数据
如何解决多线程安全问题?
- 基本思想: 让程序没有安全问题
怎么实现:
- 把多条语句操作共享数据的代码给锁起来,让任意时刻只能有一个线程执行即可
- Java提供了同步代码块的方式来解决
同步代码块的格式
synchronized(任意对象){
}
// synchronized(任意对象):就相当于给代码加上锁,任意对象就可以看成一把锁
package 案例;
public class ticket implements Runnable{
private int ticket = 100;
private Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (ticket > 0) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在买票" + ticket + "号");
ticket--;
} else {
System.out.println("今天的票已卖完,请明天再来");
System.exit(0);
}
}
}
}
}
- 好处:解决了多线程的数据安全问题
- 弊端,当线程很多时,因为每一个线程都会去判断同步上的锁,这很耗费资源,从而降低运行效率
同步方法:就是把synchronized关键字加到方法上
public synchronized void name(){}
同步方法中的synchronized 参数对象是方法所在类(this)
静态同步方法的锁对象是类的直接字节码文件synchronized (类名.class)
线程安全的类
StringBuffer:
- 线程安全,可变的字符序列
- 从版本JDK5开始,被StringBuilder替代。通常应该使用StringBuilder类,因为它支持所有相同的操作,但它更快,因为它不执行同步
Vector:
- 从Java2平台v1.2开始,该类改进了List接口,使其称为java Collections Framework 的成员。与新的集合实现不同,Vector被同步。如果不需要线程安全的实现,建议使用ArrayList代替Vector
Hashtable:
- 该类实现了应该哈希表,它将键映射到值。任何非null对象都可以用作键或者值
- 从Java2平台V1.2 开始,该类进行了改进,实现了Map接口,使其成为java Collections Framework 的成员。与新的集合实现不同,Hashtable被同步。如果不需要线程安全地实现,建议使用HashMap代替Hashtable
Lock锁
Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作
Lock中提供了获得锁和释放锁的方法
- lock():获得锁
- nulock():释放锁
Lock是接口不能直接实例化,这里采用它的实现类RnntrantLock来实例化
ReentrantLock的构造方法
- ReentrantLock():创建一个ReentrantLock的实例
package Lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyRunnable implements Runnable{
private int ticket = 100;
private Lock lock =new ReentrantLock();
// @Override
// public void run() {
// while (true) {
// lock.lock();
// if (ticket > 0) {
// try {
// Thread.sleep(100);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// System.out.println(Thread.currentThread().getName() + "正在买票" + ticket + "号");
// ticket--;
// }
// lock.unlock();
// }
// }
/*
* 以上开发虽然可以完成程序
* 但是为了规范写法
* 应该这样
* */
@Override
public void run() {
while (true) {
lock.lock();
try {
if (ticket > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在买票" + ticket + "号");
ticket--;
}
}finally {
lock.unlock();
}
}
}
}
生产者消费者模式概述
生产者消费者模式是应该非常经典的多线程协作的模式,弄懂生产者消费者问题能够让我们对多线程编程的理解更加深刻
生产者消费者主要包含了两类线程
- 一类是生产者线程用于生产数据
- 一类是消费者线程用于消费数据
为了解耦生产者和消费的关系,通常会采用共享的数据区域,就像一个仓库
- 生产者产生数据之后直接放置在共享数据中,并不需要关心消费者的行为
- 消费者只需从共享数据区中去获取数据,并不需要关系生产者的行为

为了体现生产和消费过程中的等待和唤醒,Java就提供了几个方法供我们使用,这几个方法在Object类中

案例:

package 案例;
public class Box {
private int milk = 0;
public boolean state = false;
public synchronized void put(int milk) {
this.milk = milk;
if(state){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("配送员送来了第"+milk+"瓶牛奶");
state=true;
notifyAll();
}
public synchronized void get() {
if (!state){
try {
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("小明拿到了"+milk+"瓶牛奶");
state = false;
notifyAll();
}
}
package 案例;
public class producer implements Runnable{
private Box b;
public producer(Box b) {
this.b = b;
}
@Override
public void run() {
for(int i = 1;i<=10;i++){
b.put(i);
b.state = true;
}
}
}
package 案例;
public class consumer implements Runnable{
private Box b;
public consumer(Box b) {
this.b = b;
}
@Override
public void run() {
while (true){
b.get();
}
}
}
package 案例;
public class milkDemo {
public static void main(String[] args) {
Box b = new Box();
producer producer = new producer(b);
consumer consumer = new consumer(b);
Thread pro = new Thread(producer,"生产者");
Thread con = new Thread(consumer,"消费者");
pro.start();
con.start();
}
}
网络编程
网络编程入门:
网络编程概述
计算机网络是指在地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路链接起来,在网路操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统

网络编程
- 在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换
网络编程的三要素:
-
IP
-
计算机识别的唯一标识
-
InetAddress
为了方便我们查找IP地址java提供了InetAddress类
-
-
-
端口
- 设备中程序的唯一标识
- 用两个字节的整数表示,取值范围065535.其中01023之间的端口用于运行知名的网络服务和应用,普通应用程序需要使用1024以上的端口号。如果端口号被占用应用程序会启动失败
-
协议
-
计算机网络中通信的规则
-
常见的协议:UDP和TCP
-
UDP 协议是无连接通信协议,即在数据传输时数据的发送端和接收端不建立链接

-

-
-
UDP通信原理
UDP协议是一种不可靠的网络协议,它在通信的两端各建立一个Socket对象,但是这两个Socket只是发送,接收数据的对象
注:对于基于UDP协议的通信双方而言,没有所谓的客户端和服务器的概念
Java提供了DatagramScoket类作为基于UDP协议的Socket
UDP发送数据

package 网络编程;
import java.io.IOException;
import java.net.*;
import java.nio.charset.StandardCharsets;
public class Demo1 {
public static void main(String[] args) throws IOException {
byte[] bys = "hello,word".getBytes();
DatagramSocket ds = new DatagramSocket();
DatagramPacket dp = new DatagramPacket(bys,bys.length, InetAddress.getByName("127.0.0.1"),10086);
ds.send(dp);
ds.close();
}
}
UDP接受数据

package 网络编程;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
public class Demo2 {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(10086);
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
ds.receive(dp);
byte[] datas = dp.getData();
int len = dp.getLength();
System.out.println("消息:"+new String(datas,0,len));
ds.close();
}
}
案例:聊天室
package 案例;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class SendDemo {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
while (true){
System.out.println("请输入发送的消息");
String news = sc.nextLine();
int exit = Integer.parseInt(news);
if(exit == 886){
System.out.println("exit");
break;
}else {
DatagramSocket ds = new DatagramSocket();
byte[] bytes = news.getBytes();
DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getByName("127.0.0.1"),8111);
ds.send(dp);
}
}
}
}
package 案例;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class Reception {
public static void main(String[] args) throws IOException {
DatagramSocket ds = new DatagramSocket(8111);
while (true){
byte[] bytes = new byte[1024];
DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
ds.receive(dp);
byte[] datas = dp.getData();
System.out.println("消息:"+new String(datas,0,dp.getLength()));
}
}
}
TCP通信原理



package 网络编程;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
public class Demo3 {
public static void main(String[] args) throws IOException {
Socket s = new Socket("127.0.0.1",8080);
OutputStream op = s.getOutputStream();
op.write("hello,world".getBytes());
s.close();
}
}
package 网络编程;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Demo4 {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8080);
Socket accept = ss.accept();
InputStream is = accept.getInputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = is.read(bytes)) != -1){
System.out.println(new String(bytes,0,len));
}
}
}
案例:
package 案例;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;
public class TCPSendDemo {
public static void main(String[] args) throws IOException {
Socket s = new Socket("127.0.0.1",8787);
Scanner sc = new Scanner(System.in);
OutputStream os = s.getOutputStream();
while (true) {
System.out.println("请输入消息:");
String news = sc.nextLine();
os.write(news.getBytes());
if(news.equals("886")){
break;
}
}
s.close();
}
}
package 案例;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPRecepDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8787);
Socket accept = ss.accept();
InputStream is = accept.getInputStream();
byte[] bytes = new byte[1024];
int len;
while ((len = is.read(bytes)) != -1){
System.out.println(new String(bytes,0,len));
}
}
}
案例:
package 案例;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
public class TCPRecepDemo {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8787);
Socket accept = ss.accept();
InputStream is = accept.getInputStream();
OutputStream os = new FileOutputStream("D:\\java_study\\news.txt");
byte[] bytes = new byte[1024];
int len;
while ((len = is.read(bytes)) != -1){
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
String format = df.format(new Date());// new Date()为获取当前系统时间
String sb = new String(format+"\r\n"+new String(bytes));
os.write(sb.getBytes());
}
}
}
Lambda编程思想
也叫函数式编程思想
在数学中,函数就是有输入量,输出量的一套计算方案
面对对象思想强调"必须通过对象的形式来做事情"
函数式编程思想则尽量忽略面向对象的复杂语句
案例分析:
// 实现开放一个新线程并打印 线程已经启动
// 常规方式
public class MyRunnable implements Runnable{
@Override
public void run() {
System.out.println("线程已经启动");
}
}
// rRunnableDemo
package 多线程;
public class RunnableDemo1 {
public static void main(String[] args) {
MyRunnable my = new MyRunnable();
// Thread t1 = new Thread(my);
Thread t1 = new Thread(my,"线程1");
t1.start();
ti.close();
}
}
//匿名内部类方式
new Thread(new Runnable(){
@Override
public void run() {
System.out.println("线程已经启动");
}
}).start();
// 函数式方案
new Thread(() -> {
sout("线程已经启动")
}).start()
lamdba 表达式格式
(参数)->{代码块}


Lambda的三个案例
public interface Human {
void eat();
}
public class HumanOP implements Human{
@Override
public void eat() {
System.out.println("我会吃东西了");
}
}
public class HumanDemo {
public static void main(String[] args) {
Human hunman = new HumanOP();
hunman.eat();
e(new HumanOP(){
@Override
public void eat() {
// super.eat();
System.out.println("我会吃苹果了");
}
});
e(() -> {
System.out.println("我会吃香蕉了");
});
}
public static void e (Human h){
h.eat();
}
}
public interface Flyable {
void fly(String s);
}
public class FlyableOP implements Flyable{
@Override
public void fly(String s) {
System.out.println(s);
}
}
public class FlyableDemo {
public static void main(String[] args) {
Flyable f = new FlyableOP();
useFyable(f);
String s1 = "你好吗";
useFyable(new Flyable() {
@Override
public void fly(String s) {
System.out.println("那玩意很香");
}
});
useFyable((s) -> {
System.out.println(s);
System.out.println("我真的太喜欢了");
});
}
public static void useFyable(Flyable f) {
f.fly("我喜欢吃螺蛳粉");
}
}
public interface Addable {
int add(int x,int y);
}
public class AddableDemo {
public static void main(String[] args) {
Useadd(new Addable() {
@Override
public int add(int x, int y) {
return x + y;
}
});
Useadd((int x,int y)->{
return x+y;
});
}
public static void Useadd(Addable a){
int sum = a.add(10,20);
System.out.println(sum);
}
}
省略方案:
方式一:
public int add(int x, int y) {
return x + y;
}
});
/// 参数类型 可以省略
|
|
|
^
public int add( x, y) {
return x + y;
}
});
// 注意:不能省略一个,另一个不省略
// 方式二:
useFyable(s -> System.out.println(s));
// 方式三
public int add( x, y) x + y;);
注意事项:
- 使用Lambda必须要有接口,并且要求接口中有仅有一个抽象方法
- 必须有上下文环境,才能推导出Lambda对应的接口
- 根据局部变量的赋值得知Lambda对应的接口:Runnable r = ()->sout(“Lambda”);
- 根据调用方法的参数得知Lambda对应的接口:new Thread(()->sout(“Lambda”).start());
Lambda表达式和匿名内部类的区别

接口组成更新概述
接口的组成
-
常量
public static final
-
抽象方法
public abstract
-
默认方法(Java8)
-
静态方法(Java9)
-
私有方法
默认方法:
接口中默认方法的定义格式:
- 格式:public default 返回类型 方法名 (参数列表){}
- 范例:public default void Show3(){ }
j接口中的默认方法的注意事项:
- 默认方法不是抽象方法,所以不强制被重写。但是可以被重写,重写的时候不需要加default关键字
- public 可以省略,default不能省略
package 接口组成;
public interface Inter {
void show();
void show2();
default void show3(){
System.out.println(3);
}
default void show4(){
System.out.println(4);
}
}
public class Inter1 implements Inter{
@Override
public void show() {
System.out.println(1);
}
@Override
public void show2() {
System.out.println(2);
}
}
public class InterDemo {
public static void main(String[] args) {
Inter i = new Inter1();
i.show();
i.show2();
i.show3();
i.show4();
}
}
/*
默认方法可以不重写也可以重写
默认方法可以有多个
*/
接口中的私有方法
定义格式:
- 格式1:private返回值类型 方法名(参数列表){ }
- 范例:private void show(){}
- 格式2:private static 返回值类型 方法名(参数列表){ }
- 范例2:private static void show(){}
注意:
- 默认方法可以调用私有的静态方法和非静态方法
- 静态方法只能调用私有的静态方法
package 接口组成;
public interface Number {
static void show1 (){
System.out.println("系统开始执行");
// System.out.println("一号机准备起飞");
// System.out.println("二号机准备起飞");
// System.out.println("三号机准备起飞");
method2();
System.out.println("系统执行结束");
}
static void show2(){
System.out.println("系统开始执行");
// System.out.println("一号机准备起飞");
// System.out.println("二号机准备起飞");
// System.out.println("三号机准备起飞");
// method1(); 不能访问非静态方法
method2();
System.out.println("系统执行结束");
}
private static void method2(){
System.out.println("一号机准备起飞");
System.out.println("二号机准备起飞");
System.out.println("三号机准备起飞");
} default void show4(){
System.out.println("系统开始执行");
// System.out.println("一号机准备起飞");
// System.out.println("二号机准备起飞");
// System.out.println("三号机准备起飞");
method1();
method2(); //可以调用静态方法
System.out.println("系统执行结束");
}
default void show5(){
System.out.println("系统开始执行");
// System.out.println("一号机准备起飞");
// System.out.println("二号机准备起飞");
// System.out.println("三号机准备起飞");
method1();
method2(); //可以调用静态方法
System.out.println("系统执行结束");
}
private void method1(){
System.out.println("一号机准备起飞");
System.out.println("二号机准备起飞");
System.out.println("三号机准备起飞");
}
}
package 接口组成;
public class numberDemo {
public static void main(String[] args) {
Number n1 = new numberOP();
n1.show4();
System.out.println("-----4-----");
n1.show5();
System.out.println("-----5-----");
Number.show1();
System.out.println("-----1-----");
Number.show2();
System.out.println("-----2-----");
/*
静态方法可以直接调用
*/
}
}
方法引用
方法引用符:’ :: ’
usePrintable(s -> System.out.println(s));
//利用引用符号改进后
UsePrintable(System.out::println)
//可推导的都是可省略的

package 接口组成;
public interface Printable {
void Print(int i);
}
package 接口组成;
public class PrintableDemo {
public static void main(String[] args) {
UsePrintable(i -> System.out.println(i));
UsePrintable(System.out::println);
}
public static void UsePrintable (Printable p){
p.Print(7878);
}
}
Lambda表达式支持的方法引用
常用的引用方式:
- 引用类方法
- 引用对象的实例方法
- 引用类的实例方法
- 引用构造器
引用类方法:其实就是引用类的静态方法
-
格式:类目::静态方法
-
范例::Integer::parseInt
- Integer类的方法:public static int parseInt(String s) 是将一个String 类型的数据转换为一个int类型的方法
public interface Convert { int convert(String s); } package 接口组成; public class ConvertDemo { public static void main(String[] args) { UseConvert(s -> Integer.parseInt(s)); //Lambda 表达式 UseConvert(Integer::parseInt); } public static void UseConvert(Convert c){ int convert = c.convert("1024"); System.out.println(convert); } }引用对象的实例化方法
引用对象的实例方法,其实就引用类中的成员方法
-
格式:对象::成员方法
-
范例:“HelloWorld”::toUpperCase
-
String 类中的方法:public String toUpperCase() 将此String所有字符转换为大写
public class PrintString { public void StringUpperCase (String s){ String result = s.toUpperCase(); System.out.println(result); } } public interface Printinter { void UseUpperCase(String s); } public class PrintDemo { public static void main(String[] args) { UsePrint(s -> System.out.println(s.toUpperCase())); PrintString ps = new PrintString(); UsePrint(ps::StringUpperCase); } public static void UsePrint(Printinter P){ P.UseUpperCase("Hello World"); } }引用类的实例方法
-

public interface MyString {
String mySubString(String s,int x,int y);
}
public class MyStringDemo {
public static void main(String[] args) {
useSubString((s,x,y) -> s.substring(x,y));
useSubString(String::substring);
//Lambdag表达式中
// 第一个参数作为实体对象(调用者)
//第二,第三个参数(全部参数)作为方法参数
}
public static void useSubString(MyString m){
String result = m.mySubString("hello",2,5);
System.out.println(result);
}
}
引用构造器

package Lambda;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package Lambda;
public interface StudentBuilder {
public Student builder(String name,int age);
}
package Lambda;
public class StudentDemo {
public static void main(String[] args) {
useStudentBuilder((name,age)-> new Student(name,age));
useStudentBuilder(Student::new);
}
public static void useStudentBuilder(StudentBuilder s){
Student student = s.builder("张三",18);
System.out.println(student.getName()+"\t"+student.getAge());
}
}
函数式接口

public class RunnableDemo {
public static void main(String[] args) {
RunnableTool(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"启动了");
}
});
RunnableTool(() -> System.out.println(Thread.currentThread().getName()+"qidongle"));
}
public static void RunnableTool(Runnable r){
new Thread(r).start();
}
}


反射
1.类加载




反射







模块



Jsoup





public class Demo1 {
public static void main(String[] args) throws IOException {
URL url = new URL("http://music.xirang.ltd/");
Document document = Jsoup.parse(url,10000);
System.out.println(document);
}
}




注:cssquery 需要selector类

569

被折叠的 条评论
为什么被折叠?



