Java
常用DOS命令
| 操作 | 说明 |
|---|---|
| 盘符名称: | 盘符切换。E:回车,表示切换到E盘。 |
| dir | 查看当前路径下的内容 |
| cd目录 | 进入单级目录。cd itheima |
| cd .. | 回退到上一级目录 |
| cd 目录1\目录2\ .. | 进入多级目录。cd itheima\JavaSE |
| cd \ | 回退到盘符目录 |
| cls | 清屏 |
| exit | 退出命令提示符窗口 |
HelloWorld
-
建立 HelloWorld.java 文件
public class HelloWorld { public static void main(String[] args){ System.out.println("HelloWorld"); } } -
打开命令行窗口,cd进入HelloWorld.java 文件所在的目录
-
输入 javac HelloWorld.java
-
在输入 java HelloWorld.java
类型
-
大致和c++一样
-
注意:
- long a = 10000L
- float a = 3.14F
-
(等级最低)byte,short,char -> int -> long -> float -> double(等级最高)
- 多个不同类型数运算,其结果的类型与参与运算的数钟最高级类型数相同
数据输入
-
导包
import java.util.Scanner; // 导包的动作必须出现在类定义的上边 -
创建对象
Scanner sc = new Scanner(System.in); // 上面这个格式里面,只有sc是变量名,可以变,其他的都不允许变 -
接收数据
int i = sc.nextInt(); // 上面这个格式里面,只有i是变量名,可以变,其他的都不允许变。
IDEA项目结构
- 创建一个空项目
- 创建一个新模块(idea_test)
- 在idea_test模块下的src下创建了一个包(com.itheima)
- 在com.itheima包下新建一个类(HelloWorld)
- 在HelloWorld类中编写代码
- 在idea中执行程序
快捷键
-
内容辅助键
Ctrl + Alt + 空格
-
快速生成main()方法
psvm,回车
-
快速生成输出语句
sout,回车
-
格式化
Ctrl + Alt + L
-
快速生成左式
Ctrl + Alt + V
-
快速生成 get() 和 set()\
Alt + Insert
-
退出系统
System.exit( 0 )
数组
int[] arr
// 数组动态初始化
int[] arr = new int[3]
// 数据静态初始化
int[] arr = new int[]{1,2,3,......};
int[] arr = {1,2,3,......}
内存分配
- 栈内存:存储局部变量
- 堆内存:存储new出来的内容(实体,对象)
继承
-
调用子类的构造函数时,会同时调用父类的无参构造函数;
-
只支持单继承,不支持多继承
-
支持多层继承
-
extends
public class Zi extends Fu{
}
- super()
// 父类和子类都有 call() 通过方法重写,在父类的 call() 基础上增加子类需要的功能。
public class NewPhone extends Phone {
public void call(String name){
System.out.println("开启视频功能");
super.call(name)
}
}
- @Override
包
- 相当于一个文件夹,里面装的是类
// 带包的java类编译和执行
// 例子,包名是 com.itheima,文件名叫 HelloWorld.java
// 手动建包
// 按以前的格式编译Java文件
javac HelloWorld.java
// 手动创建包:在E盘建立文件夹com,然后在com下建立文件夹itheima
// 把HelloWorld.class文件放到包的最里面
// 执行 java com.itheima.HelloWorld
--------------------------------------------------------------
// 自动建包
javac -d . HelloWorld.java
java com.itheima.HelloWorld
- 关于权限问题
_final
- 修饰方法:表明该方法是最终方法,不能被重写
- 修饰变量:表明该变量是常量,不能再次被赋值
- 修饰类:表明该类是最终类,不能被继承。
public final class FU {
public final int age = 18;
public final void method(){}
}
_final修饰局部变量
- 变量是基本类型:final 修饰指的是基本类型的数据值不能发生改变
- 变量是引用类型:final 修饰指的是引用类型的地址值不能发生改变,但是地址里面的内容可以发生改变的
_static
-
被类的所有对象共享
-
通过类名. 来调用
public class Student{ public static String name; } ------------------------------------------ public class StudentManager{ public static void main(String[] args){ Student.name = "番禺中学" // 后面所有 Student 的对象的 name 都是番禺中学 Student s = new Student(); } }
static 访问特点:
-
非静态的成员方法
- 能访问静态的成员变量
- 能访问非静态的成员变量
- 能访问静态的成员方法
- 能访问非静态的成员方法
-
静态的成员方法
- 能访问静态的成员变量
- 能访问静态的成员方法
多态(多态转型)
-
成员变量:编译看父,执行看父
-
成员方法:编译看父,执行看子
-
多态中的转型
-
向上转型
-
从子到父
-
父类引用指向子类对象
Animal a = new Cat(); a.eat();
-
-
向下转型
-
从父到子
-
父类引用转为子类对象
Animal a = new Cat(); Cat c = (Cat)a;
-
-
抽象类的特点
-
抽象类和抽象方法必须使用abstract关键字修饰
- public abstract class 类名 {}
- public abstract void eat {}
-
抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类
-
抽象类不能实例化
- 抽象类如何实例化?
- 参照多态的方式,通过子类对象实例化,这叫抽象类多态
- 抽象类如何实例化?
-
抽象类的子类
- 要么重写抽象类中的所有抽象方法
- 要么是抽象类
抽象类的成员特征
-
成员变量
- 可以是变量
- 也可以是常量
-
构造方法
- 有构造方法,但不能实例化
- 用于子类访问父类数据的初始化
-
成员方法
- 可以有抽象方法:限定子类必须完成某些动作
- 也可以有非抽象方法:提高代码复用性
接口
-
类可以有多个接口
-
创建接口:
interface -> 接口名 -
类实现接口用 implements 实现:
public class 类名 implements 接口名 {} -
接口不能实例化,可参照多态的方式,通过实现类对象实例化,这叫接口多态
package Test05; public interface Jumpping { public abstract void Jump(); } ---------------------------------------------- package Test05; public class Cat implements Jumpping{ @Override public void Jump() { System.out.println("猫可以调高高"); } } ----------------------------------------------- package Test05; public class JumppingDemo { public static void main(String[] args) { Jumpping j = new Cat(); j.Jump(); } }接口成员特点
- 成员变量
- 只能是常量
- 默认修饰符:public static final int num; (所以只写 int num 即可)
- 构造方法
- 接口没有构造方法,因为接口主要是对行为进行抽象的,是没有具体存在
- 一个类如果没有父类,默认继承自 Object 类
- 成员方法
- 只能是抽象方法
- 默认修饰符:public abstract void Jump();(所以只写 void Jump() 即可)
- 成员变量
接口与抽象类的区别
- 成员区别
- 抽象类:变量,常量,构造方法,抽象方法,非抽象方法
- 接口:常量,抽象方法
- 关系区别
- 类与类:继承,单继承
- 类与接口:实现,可以单实现,也可以多实现
- 接口与接口:继承,单继承,多继承
类名作为形参和返回值
- 方法的形参是类名,其实需要的是该类的对象
- 方法的返回值是类名,其实返回的是该类的对象
抽象类名作为形参和返回值
- 方法的形参是抽象类名,其实需要的是该抽象类的子类对象
- 方法的返回值是抽象类名,其实返回的是该抽象类的子类对象
接口名作为形参和返回值
- 方法的形参是接口名,其实需要的是该接口的实现对象
- 方法的返回值是接口名,其实返回的是该接口的实现类对象
内部类的访问特点
- 内部类可以直接访问外部类的成员,包括私有
- 外部类要访问内部类的成员,必须创建对象
- 创建格式:
- 外部类名.内部类名 对象名 = new 外部类对象().内部类对象()
成员内部类
public class Outer {
private int num = 10;
/* public class Inner {
public void show() {
System.out.println(num);
}
} */
private class Inner {
public void show() {
System.out.println(num);
}
public void method(){
Inner i = new Inner();
i.show();
}
}
//执行:
public class Demo{
public static void main(String[] args){
/*Inner i = new Inner();
Outer.Inner oi = new Outer().new Inner();
oi.show();*/
Outer o = new Outer();
o.method();
}
}
局部内部类
-
局部内部类是在方法中定义的类,所以外界是无法直接使用的,需要在方法内部创建对象并使用该类可以直接访问外部类的成员,也可以访问方法内的局部变量
public class Outer { private int num = 10; public void method(){ int num2 = 20; class Inner{ public void show(){ System.out.println(num); System.out.println(num2); } } Inner i = new Inner(); i.show(); } } //执行: public class Demo{ public static void main(String[] args){ Outer o = new Outer(); o.method(); } }
局部-匿名内部类
-
存在一个类或者接口,这里的类可以是具体类也可以是抽象类
// 存在一个接口 public interface Inter { void show(); } // 匿名内部类两种格式 public class Outer { public void method() { /*new Inter(){ @Override public void show() { System.out.println("匿名内部类"); } }.show();*/ // 实现多次调用的方法👇👇👇 Inter i = new Inter() { @Override public void show() { System.out.println("匿名内部类"); } }; i.show(); i.show(); } }-
开发中使用:
// 存在一个接口 public interface Inter { void jump(); } // 无需接口的实现类 public class Outer { public void method(Inter i) { i.jump(); } } // 执行: public class Demo { public static void main(String[] args) { Outer o = new Outer(); o.method(new Inter() { @Override public void jump() { System.out.println("猫猫跳高高啦"); } }); } }
-
常用API
Random
import java.util.Random;
Random r = new Random();
// 随机1-100数字
int x = r.nextInt(100)+1;
String
StringBuilder
// 将数组转换为字符串输出
public static String arrayToString(int[] arr){
StringBuilder sb = new StringBuilder();
sb.append("[");
for(int i = 0; i < arr.length; i++){
if(i == arr.length - 1){
sb.append(arr[i]);
}else{
sb.append(arr[i]).append(",");
}
}
sb.append("]");
String s = sb.toString();
return s;
}
Math
public class Demo {
public static void main(String[] args) {
// 绝对值
System.out.println(Math.abs(-88));
// 向上取整
System.out.println(Math.ceil(12.88));
// 向下取整
System.out.println(Math.floor(12.99));
// 按照四舍五入
System.out.println(Math.round(12.66F));
// 返回较大值
System.out.println(Math.max(66,88));
// 返回较小值
System.out.println(Math.min(66,88));
// 返回a的b次幂
System.out.println(Math.pow(2.0,3.0));
// 随机返回double的正值[0.0,1.0)
System.out.println((int)(Math.random()*100)+1);
}
}
System
public class Demo2 {
public static void main(String[] args) {
//结束程序
// System.exit(0);
//返回目前的时间(以毫秒为单位)
System.out.println(System.currentTimeMillis() * 1.0/1000/60/60/24/365 + "年");
}
}
Object( toString() )
-
返回对象的字符串表示形式。建议所有子类重写该方法,自动生成
Alt + Ins + toString()@Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
Object( equals() )
-
比较对象是否相等,默认比较地址,重写可以比较内容,自动生成
Alt + Ins + equals()@Override public boolean equals(Object o) { //判断地址是否相同 if (this == o) return true; //判断参数是否为NULL //判断两个对象是否来自同一个类 if (o == null || getClass() != o.getClass()) return false; //向下转型 Person person = (Person) o; //比较年龄是否相同 if (age != person.age) return false; //比较姓名是否相同 return name != null ? name.equals(person.name) : person.name == null; }
Arrays
- Arrays.toString() 、Arrays.sort()
import java.util.Arrays;
public class ArraysDemo{
public static void main(String[] args){
int[] arr = {23,345,123,5,2,68};
System.out.println(Arrays.toString(arr));
//升序
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
}
冒泡排序
for(int i = 0;i<arr.length-1;i++){
for (int j = 0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
基本类型包装类
Integer
- Integer.valueOf( )
Integer i = Integer.valueOf(100);
System.out.println(i);
Integer i2 = Integer.valueOf("232");
System.out.println(i2);
int 和 String 相互转换
- intValue()
- Integer.parseInt()
public class Demo06 {
public static void main(String[] args) {
// Int -> String : Way01
int n = 100;
String s = "" + n;
System.out.println(s);
// Int -> String : Way02
String s2 = String.valueOf(n);
System.out.println(s2);
//String -> Integer -> int : Way01
String s3 = "100";
Integer i = Integer.valueOf(s3);
int x = i.intValue();
System.out.println(x);
//String -> (Integer) -> int : Way02
//跳过了Integer
int y = Integer.parseInt(s3);
System.out.println(y);
}
}
案例
- Test11
自动装箱和拆箱
-
装箱:把基本数据类型转换为对应的包装类类型
Integer i = Integer.valueOf(100);//装箱 Integer i2 = 100;//自动装箱 -
拆箱:把包装类类型转换为对应的基本数据类型
Integer i = Integer.valueOf(100); Integer i2 = 100; i2 = i2.intValue() +200;//拆箱 i2 += 200;//自动拆箱 -
注意:在使用包装类类型时,如果做操作,最好先判断是否为null;只要是对象,在使用前就必须进行不为null的判断
日期类 _Date
Date d = new Date();
System.out.println(d);
//👇👇👇从1970 00:00:00起的毫秒数
long date = 1000*60*60;
Date d2 = new Date(date);
System.out.println(d2);
// getTime()
Date d = new Date();
System.out.println(d.getTime() * 1.0/1000/60/60/24/365 + "年");
// setTime()
long time = System.currentTimeMillis();
d.setTime(time);
SimpleDateFormat
//日期格式化
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d);
System.out.println(s);
//解析日期
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String ss = "2048-07-15 10:46:48";
Date dd = sdf2.parse(ss);
System.out.println(dd);
日期工具
// Date -> String
// 要import java.util.Date;
public static String dateTOString(Date date, String format){
SimpleDateFormat sdf = new SimpleDateFormat(format);
String d = sdf.format(date);
return d;
}
// String -> Date
public static Date StringTodate(String s, String format) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat(format);
Date d = sdf.parse(s);
return d;
}
Calendar
// Calendar提供了一个类的方法 getInstance 用于获取 Calendar 对象
Calendar c = Calendar.getInstance();
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH) + 1;
int date = c.get(Calendar.DATE);
System.out.println(year + "," + month + "," + date);
// 输出结果为 2022,7,15
Calendar.add()
Calendar c = Calendar.getInstance();
c.add(Calendar.YEAR, 10);//年份增加 10
c.add(Calendar.DATE, -5);//天数减少 5
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH) + 1;
int date = c.get(Calendar.DATE);
System.out.println(year + "," + month + "," + date);
// 输出结果为 2032,7,10
Calendar.set()
Calendar c = Calendar.getInstance();
c.set(2050,7,15);
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH) + 1;
int date = c.get(Calendar.DATE);
System.out.println(year + "," + month + "," + date);
// 输出结果为 2050,8,15
异常
- Error:严重问题,不需要处理
- Exception:称为异常类,它表示程序本身可以处理的问题
- RuntimeException(运行时异常):在编译期是不检查的,出现问题后,需要我们回来修改代码。
- 非 RuntimeException:编译期就必须处理的,否则程序不能通过编译,就更不能正常运行了。
try...catch...
try {
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}
- ArrayIndexOutOfBoundsException.printStackTrace()
public class Demo {
public static void main(String[] args) {
method();
System.out.println("运行结束");
}
public static void method(){
try {
int[] arr ={1,2,3};
System.out.println(arr[3]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("出现异常,跳过执行");
e.printStackTrace();
}
}
}
Throwable 的成员方法
- String getMessage()
- System.out.println(e.getMessage()) 输出的是简单异常信息
- String toString()
- System.out.println(e.toString()) 输出的是较为详细异常信息
- void printStackTrace()
- e.printStackTrace 输出最详细的异常信息(异常类名,原因,位置)
throws
throws 异常类名
自定义异常
// 自定义异常类
public class ScoreException extends Exception{
public ScoreException(){}
public ScoreException(String message){
super(message);
}
}
// throw 异常的类
public class Teacher {
public void check(int score) throws ScoreException {
if(score<0|| score>100){
throw new ScoreException("你的分数有误");
}else {
System.out.println("分数正常");
}
}
}
// 执行
public class Demo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Teacher t = new Teacher();
int score = sc.nextInt();
try {
t.check(score);
} catch (ScoreException e) {
e.printStackTrace();
}
}
}
throws 与 throw 的区别
- throws
- 用在方法声明后面,跟的是异常类名
- 表示抛出异常,由该方法的调用者来处理
- 表示出现异常的一种可能性,并不一定会发生这些异常
- throw
- 用在方法体内,跟的是异常对象名
- 表示抛出异常,由方法体内的语句处理
- 执行 throw 一定抛出了某种异常
Collection
- 单列集合
Collection<String> c = new ArrayList<String>();
//添加元素
c.add("hello");
c.add("world");
c.add("java");
//移除某个元素
c.remove("java");
//清楚所有元素
c.clear();
//判断是否有 hello 元素,此时返回值为false
c.contains("hello");
//判断集合是否为空,此时返回true
c.isEmpty();
//返回集合长度
c.size();
Collection 遍历
- Iterator -- 迭代器,集合的专用遍历方式
- next()、hasNext()
Collection<String> c = new ArrayList<String>();
//添加元素
c.add("hello");
c.add("world");
c.add("java");
Iterator<String> it = c.iterator();
System.out.println(it.next());
System.out.println(it.next());
System.out.println(it.next());
//因为集合里只有三个元素,执行第四次System.out.println(it.next())会报异常;
//👇👇👇复习了一下异常处理👇👇👇
try {
System.out.println(it.next());
}catch (NoSuchElementException e){
System.out.println("结束");
}
//boolean hasNext():返回迭代具有更多元素,则返回true
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
List集合(ArrayList的父亲)
-
有序集合,用户可以精确控制列表中每个元素的插入位置,用户可以通过整数索引访问元素,并搜索列表中的元素。
-
List(接口):可重复
-
特有方法(继承给了ArrayList):
add(index, element)、remove(index)、set(index, element)、size()、get(index)
-
遍历:
-
因为List继承了Collection,所以可以通过迭代器
Iterator<String> it = List.iterator(); -
通过for循环调用get()
for(int i=0;i<list.size();i++){ String s = list.get(i); System.out.println(s); }
-
-
迭代器-并发修改异常:
- 解决方法,换成for循环遍历,调用get()进行修改
ListIterator
-
next()、hasNext()、previous()、hasPrevious()、add(E e)
List<String> list = new ArrayList<>(); list.add("hello"); list.add("world"); list.add("java"); ListIterator<String> lit = list.listIterator(); while (lit.hasNext()){ String s = lit.next(); System.out.println(s); } while (lit.hasPrevious()){ String s = lit.previous(); System.out.println(s); } -
不会发生并发修改异常
ListIterator<String> lit2 = list.listIterator();
while (lit2.hasNext()){
String s = lit2.next();
if(s.equals("world")){
lit2.add("py");
}
}
增强for循环
- 简化数组和Collection集合的遍历
- 内部原理是一个Iterator迭代器
int[] arr = {1,2,3,4,5};
for(int i : arr){
System.out.println(i);
}
//👇会抛出并发修改异常
for(int i : arr){
if(s.equals(1)){
lit2.add(2);
}
}
ArrayList
-
底层数据结构是数组
-
查询快,增删慢
import java.util.ArrayList;
LinkedList
-
底层数据结构是链表
-
查询慢,增删快
-
功能:
- addFirst(E e)、addLast(E e)、getFirst()、getLast()、removeFirst()、removeLast()
Set
-
Set(接口):不可重复,由HashSet<>()实现类实现
-
没有带索引的方法,所以不能使用普通for循环遍历
Set<String> set = new HashSet<String>(); set.add("hello"); set.add("world"); set.add("java"); for (String i : set){ System.out.println(i); }
哈希值 hashCode()
- 哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
- 默认情况下,不同对象的哈希值是不相同的,同一个对象多次调用hashCode()返回的哈希值是相同的
- 通过方法重写,可以实现不同对象的哈希值是相同的
Student s1 = new Student("林青霞",30);
System.out.println(s1.hashCode());//381259350
System.out.println(s1.hashCode());//381259350
Student s2 = new Student("卢本伟",30);
System.out.println(s2.hashCode());//2129789493
System.out.println("hello".hashCode());//99162322
System.out.println("world".hashCode());//113318802
HashSet 集合
- 是Set的实现类,不可重复
- 没有带索引的方法,所以不能使用普通for循环遍历
HashSet<String> hs = new HashSet<String>()
- ☢注意:保证存储学生对象时唯一性,需要在学生类中重写hashCode()和equals()方法(自动生成即可)
LinkedHashSet 集合
- 继承HashSet
- 哈希表和链表实现的Set接口,具有可预测的迭代次序
- 有哈希表保证元素唯一,也就是说没有重复的元素
TreeSet 集合
-
元素有序:这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
- TreeSet():根据其元素的自然排序(升序,让元素所属的类实现Comparable接口,重写compareTo(T o)方法)进行排序
- TreeSet(Comparator comparator):根据指定的比较器进行排序
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int num = o1.getAge() - o2.getAge();
int num2 = num==0?o1.getName().compareTo(o2.getName()):num;
return num2;
}
});
-
没有带索引的方法,所以不能使用普通for循环遍历
-
是Set集合,不包含重复元素
Comparator比较器的使用
Collections
基本使用
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(30);
list.add(20);
list.add(10);
list.add(40);
list.add(50);
//升序
Collections.sort(list);
System.out.println(list);//[10, 20, 30, 40, 50]
//反转顺序
Collections.reverse(list);
System.out.println(list);//[50, 40, 30, 20, 10]
//随机顺序
Collections.shuffle(list);
System.out.println(list);//[40, 10, 20, 30, 50]
Collections.shuffle(list);
System.out.println(list);//[10, 30, 40, 20, 50]
}
Collections的自然排序处理
public static void main(String[] args) {
ArrayList<Student> array = new ArrayList<Student>();
Student s1 = new Student("lzl", 10);
Student s2 = new Student("lzh", 11);
array.add(s1);
array.add(s2);
//调用collections对ArrayList集合排序
//sort(list<T> list, Comparator<? super T> c)
Collections.sort(array, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
int num = o1.getAge() - o2.getAge();
int num2 = num == 0 ? o1.getName().compareTo(o2.getName()) : num;
return num2;
}
});
for (Student s:array){
System.out.println(s.getAge()+","+s.getName());
}
}
泛型
- <类型>:指定一种类型的格式
- 好处:把运行时的问题提前到了编译期间;避免了强制类型转换
泛型类
// 定义泛型类
public class Generic<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
// 使用泛型类
public class TDemo {
public static void main(String[] args) {
Generic<String> t1 = new Generic<String>();
t1.setT("库里");
System.out.println(t1.getT());
Generic<Integer> t2 = new Generic<Integer>();
t2.setT(30);
System.out.println(t2.getT());
}
}
泛型方法
//泛型方法定义:
//普通泛型方法
public void show(T t){
System.out.println(t);
}
//改进泛型方法
public <T> void show2(T t){
System.out.println(t);
}
//泛型方法使用
public class TDemo {
public static void main(String[] args) {
//使用普通泛型方法
Generic<String> t1 = new Generic<String>();
Generic<Integer> t2 = new Generic<Integer>();
t1.show("卢本伟");
t2.show(30);
//使用改进泛型方法
Generic refine = new Generic();
refine.show2("卢本伟");
refine.show2(30);
}
}
泛型接口
//定义泛型接口
public interface Generic2<T>{
void show(T t);
}
//定义泛型接口实现类
public class GenericImpl<T> implements Generic2{
@Override
public void show(Object o) {
System.out.println(o);
}
}
//使用泛型接口
public class Demo {
public static void main(String[] args) {
Generic2<String> g = new GenericImpl<String>();
g.show("李胶恒");
Generic2<Integer> g2 = new GenericImpl<Integer>();
g2.show(30);
}
}
类型通配符
List<?> list1 =new ArrayList<Object>();
List<?> list2 =new ArrayList<String>();
List<?> list3 =new ArrayList<Integer>();
//类型通配符上限
List<? extends Number> list4 = new ArrayList<Number>();
List<? extends Number> list5 = new ArrayList<Integer>();
// List<? extends Number> list6 = new ArrayList<Object>();//报错
//类型通配符下限
List<? super Number> list7 = new ArrayList<Number>();
// List<? super Number> list9 = new ArrayList<Integer>();//报错
可变参数
public class Demo2 {
public static void main(String[] args) {
System.out.println(sum(10,20,30,40));
System.out.println(sum(20,30));
}
public static int sum(int... a) {
int sum = 0;
for (int i : a) {
sum += i;
}
return sum;
}
}
Map
-
Interface Map (K:键的类型,V:值的类型),HashMap为其实现类
-
将键映射到值的对象,不能包含重复的键;每个键可以映射到最多一个值;
-
案例:学生的学号和姓名中,学号为键,姓名为值
基本功能
- put(K, V):添加元素
- remove(K):通过键删除对应元素
- clear():清除所有键对应的元素
- containKey(K):判断集合是否包含指定键
- containsValue(V):判断集合是否包含指定的值
- isEmpty():判断集合是否为空
- size():集合长度,即键的个数
- get(E):根据键获得值
Map<String,String> map = new HashMap<String,String>();
map.put("202111701418","劳智乐");
map.put("202111701419","李泽恒");
map.put("202111701419","iu");//修改202111701419键所对应的值
System.out.println(map);
获取功能
- get(E):根据键获得值
- Set keySet():获得所有键的集合
- Collection values():获取所有值的集合
Map<String,String> map = new HashMap<String,String>();
map.put("202111701419","李泽恒");
// get(E):根据键获得值
System.out.println(map.get("202111701419"));
// Set<K> keySet():获得所有键的集合
Set<String> keySet = map.keySet();
for (String i : keySet) {
System.out.println(i);
}
// Collection<V> values():获取所有值的集合
Collection<String> values = map.values();
for (String val : values) {
System.out.println(val);
}
Map集合遍历
法一
- Set<Map.Entry<K,V>> entrySet():获取所有键值对对象的集合
- 增强for,得到每一个Map.Entry
- getKey()获取键、getValue()获取值
Map<String, String> map = new HashMap<String, String>();
map.put("202111701418", "劳智乐");
map.put("202111701419", "李泽恒");
Set<Map.Entry<String,String>> entrySet = map.entrySet();
for (Map.Entry<String,String> m : entrySet){
String key = m.getKey();
String value = m.getValue();
System.out.println(key+","+value);
}
☢注意:保证存储学生对象时唯一性,需要在学生类中重写hashCode()和equals()方法(自动生成即可)
法二
-
通过Set keySet():获得所有键的集合
Set<String> keySet = map.keySet() -
通过增强for遍历每一个keySet,并通过map.get(KeySet)获得值
集合嵌套
ArrayList<HashMap<String,String>> array = new ArrayList<HashMap<String,String>>();
HashMap<String,String> map1 = new HashMap<String,String>();
map1.put("孙策","大乔");
map1.put("周瑜","小乔");
array.add(map1);
HashMap<String,String> map2 = new HashMap<String,String>();
map2.put("库里","阿耶莎");
map2.put("詹姆斯","詹密");
array.add(map2);
for (HashMap<String,String> a:array){
Set<String> keySet = a.keySet();
for (String key:keySet){
String value = a.get(key);
System.out.println(value);
}
}
通过HashMap进行字符统计
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String demo = sc.nextLine();
//创建一个空的HashMap集合,key为字符,value为出现的次数
HashMap<Character,Integer> hm = new HashMap<Character,Integer>();
for (int i=0;i<demo.length();i++){
char key = demo.charAt(i);
Integer itn = hm.get(key);
if(itn == null){
hm.put(key,1);
}
else {
itn++;
hm.put(key,itn);
}
}
StringBuilder sb = new StringBuilder();
Set<Character> keySet = hm.keySet();
for (Character ct : keySet){
Integer value = hm.get(ct);
sb.append(ct).append("(").append(value).append(")");
}
String s = sb.toString();
System.out.println(s);
}
IO流
-
按数据流向分类:
-
输入流:读数据(硬盘 -> 程序)
-
输出流:写数据(程序 -> 硬盘)
-
-
按数据类型来分:
- 字节流(万能)
- 字符流
File类构造方法
public static void main(String[] args) {
//法一
File f1 = new File("E:\\Demo\\java.txt");
System.out.println(f1);
//法二
File f2 = new File("E:\\Demo", "java.txt");
System.out.println(f2);
//法三
File f3 = new File("E:\\Demo");
File f4 = new File(f3, "java.txt");
System.out.println(f4);
}
File类创建功能
- createNewFile() 创建文件、mkdir() 创建目录、mkdirs() 创建多级目录
public static void main(String[] args) throws IOException {
//创建文件
File f1 =new File("E:\\Demo\\java.txt");
System.out.println(f1.createNewFile());
//创建目录
File f2 = new File("E:\\Demo\\javaDemo");
System.out.println(f2.mkdir());
//创建多级目录
File f3 = new File("E:\\Demo\\javaDemo2\\javademo");
System.out.println(f3.mkdirs());
}
File类判断及其获取功能
Flie类删除功能
- 要想删目录,需要先将目录中内容删除干净
f.delete();
字节流
- 字节流抽象基类:
- InputStream:这个抽象类是表示字节输入流的所有类的超类
- OutputStream:这个抽象类是表示字节输出流的所有类的超类
- 子类名特点:子类名称都是以其父类名作为子类名的后缀
FileOutputStream(String name)
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("E:\\Demo\\demo.txt");
fos.write(97);//a
fos.close();//关闭流
}
写输出方法
public static void main(String[] args) throws IOException {
FileOutputStream fos = new FileOutputStream("E:\\Demo\\demo.txt");
//方法一
fos.write(97);//a
//方法二
// byte[] bys = "abcde".getBytes();
byte[] bys = {97,98,99,100};
fos.write(bys);//abcd
//方法三
fos.write(bys,1,3);//bcd
fos.close();//关闭流
}
换行问题
-
window:\r\n
-
linux:\n
-
mac:\r
fos.write("\r\n".getBytes)
接着写问题
-
添加第二个参数:true
FileOutputStream fos = new FileOutputStream("E:\\Demo\\demo.txt", true);
字节缓冲流
BufferedOutputStream(OutputStream out)
- 通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每一个字节导致底层系统的调用
BufferedInputStream(InputStream in)
- 创建BufferedInputStream将创建一个内部缓冲区数组,当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节。
public static void main(String[] args) throws IOException {
/* FileOutputStream fos =new FileOutputStream("E:\\Demo\\demo.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
bos.write("hello\r\n".getBytes());
bos.close();*/
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("E:\\Demo\\java.txt"));
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("E:\\Demo\\demo.txt"));
/*int by;
while ((by = bis.read()) != -1){
System.out.println((char)by);
}*/
byte[] bys = new byte[1024] ;
int len;
while ((len = bis.read(bys)) != -1){
System.out.println(new String(bys,0,len));
}
}
字符流
Reader
- 字符输入流的抽象类
Writer
- 字符输出流的抽象类
InputStreamReader
OutputStreamWriter
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\Demo\\demo.txt",true));
osw.write("中国万岁");
osw.close();
InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\Demo\\demo.txt"));
int ch;
while ((ch = isr.read()) != -1){
System.out.println((char)ch);
}
}
写数据
- flush():刷新流
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\Demo\\java.txt"));
osw.write(97);
//刷新流
osw.flush();
osw.write(98);
osw.flush();
osw.write(99);
//关闭流之前会在刷新一次
osw.close();
}
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("E:\\Demo\\java.txt"));
char[] chs = {'a','b','c','d','e'};
osw.write(chs);
osw.write(chs,0,chs.length);
osw.write(chs,1,3);
osw.write("abcde");
osw.write("abcde",0,"abcde".length());
osw.write("abcde",1,3);
osw.close();
}
读数据
public static void main(String[] args) throws IOException {
InputStreamReader isr = new InputStreamReader(new FileInputStream("E:\\Demo\\java.txt"));
int ch;
while ((ch=isr.read()) != -1){
System.out.println((char)ch);
}
char[] chs = new char[1024];
int len;
while ((len = isr.read(chs)) != -1){
System.out.println(new String(chs,0,len));
}
isr.close();
}
案例:复制Java文件
- FileReader 代替 InputStreamReader
- FileWriter 代替 OutputStreamWriter
public static void main(String[] args) throws IOException {
FileReader fis = new FileReader("E:\\Demo\\demo.txt");
FileWriter fos = new FileWriter("E:\\Test\\demo.txt");
/*int ch;
while ((ch = fis.read()) != -1){
fos.write(ch);
}*/
char[] chs = new char[1024];
int len;
while ((len = fis.read(chs)) != -1){
fos.write(chs,0 ,len);
}
fis.close();
fos.close();
}
字符缓冲流
- BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高效写入,可以指定缓冲区大小,或者可以接受默认大小,默认值足够大,可用于大多数用途;
- BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效读取,可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途。
public static void main(String[] args) throws IOException {
/*FileWriter fw = new FileWriter("E:\\Demo\\java.txt");
BufferedWriter bw = new BufferedWriter(fw);*/
BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\Demo\\java.txt"))
bw.write("hello\r\n");
bw.write("world\r\n");
bw.close();
BufferedReader br = new BufferedReader(new FileReader("E:\\Demo\\java.txt"));
/*int ch;
while ((ch = fis.read()) != -1){
fos.write(ch);
}*/
char[] chs = new char[1024];
int len;
while ((len = br.read(chs)) != -1){
System.out.println(new String(chs,0 ,len));;
}
br.close();
}
BufferedWriter:newLine()
- 换行
BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\Demo\\java.txt"))
bw.write("hello\r\n");
bw.newLine();
bw.flush;
BufferedReader:readLine()
String line;
while((line = br.readLine()) != null){
System.out.println(line);;
}
集合到文件
public static void main(String[] args) throws IOException {
ArrayList<String> array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
BufferedWriter bw = new BufferedWriter(new FileWriter("E:\\Demo\\demo.txt"));
for (String s : array){
bw.write(s);
bw.newLine();
bw.flush();
}
bw.close();
}
文件到集合
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("E:\\Demo\\demo.txt"));
ArrayList<String> array = new ArrayList<String>();
String line;
while((line = br.readLine()) != null){
array.add(line);
}
br.close();
for (String s:array){
System.out.println(s);
}
}
复制文件的处理
- JDK7的改进方案
try(FileWriter fw = new FileWriter("E:\\Demo\\java.txt");
FileReader fr = new FileReader("E:\\Demo\\java.txt");) {
char[] chs = new char[1024];
int len;
while ((len = fr.read(chs)) != -1){
fw.write(len);
}
}catch (IOException e) {
e.printStackTrace();
}
标准输入流
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入一个字符串:");
String line = br.readLine();
System.out.println("你输入的字符串是," + line);
System.out.println("请输入一个整数:");
int i = Integer.parseInt(br.readLine());
System.out.println("你输入的整数是:" + i);
}
//由于以上太麻烦,Java提供了一个类---Scanner
Scanner sc = new Scanner(System.in)
标准输出流
PrintStream ps = System.out;
ps.print("hello");
ps.println("hello");
// == System.out.println("hello");
字节打印流
PrintStream ps = new PrintStream("E:\\Demo\\java.txt")
ps.write(97)//a
ps.print(97);//97
ps.close();
字符打印流
PrintWrite pw = new PrintWriter(new FileWriter("E:\\Demo\\java.txt"));
pw.println("hello");
pw.flush;
//自动刷新
PrintWrite pw = new PrintWriter(new FileWriter("E:\\Demo\\java.txt"),true);
pw.println("hello");
pw.close();
对象序列化流
- ❗❕❗❕ 学生类需要实现 Serializable 序列化接口
- 序列化接口不需要重写方法
public static void main(String[] args) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:\\Demo\\java.txt"));
Student s = new Student("林青霞",30);
oos.writeObject(s);
oos.close();
}
对象反序列化流
- ObjectInputStream 反序列化先前使用 ObjectOutputStream 编写的原始数据和对象
public static void main(String[] args) throws IOException{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:\\Demo\\java.txt"));
Object obj = ois.readObject();
Student s =(Student) obj;
System.out.println(s.getName()+s.getAge());
ois.close();
}
对象序列化流
- 用对象序列化流序列化了一个对象后,假如我们修改了对象所属的类文件,读取数据会出问题。
- 给对象所属的类加一个serialVersionUID
- private static final long seriaVersionUID = 42L;
- 给该成员变量加transient关键字修饰,该关键字标记的成员变量不参与序列化过程。
递归
递归求阶层
public static int jc(int n) {
if (n == 1) {
return 1;
} else {
return n * jc(n);
}
}
遍历目录
public static void main(String[] args) throws IOException {
File srcFile2 = new File("E:\\Demo\\javaDemo\\java.txt");
System.out.println(srcFile2.createNewFile());
File srcFile = new File("E:\\Demo");
getAllFilePath(srcFile);
}
public static void getAllFilePath(File srcFile){
File[] fileArray = srcFile.listFiles();
if(fileArray != null){
for(File file : fileArray){
if (file.isDirectory()){
getAllFilePath(file);
}else {
System.out.println(file.getAbsolutePath());
}
}
}
}
Properties
- Properties作为Map集合
public static void main(String[] args) {
Properties prop = new Properties();
prop.put("itheima001","林青霞");
prop.put("itheima002","李泽和");
prop.put("itheima009","郭蜥蜴");
Set<Object> keySet = prop.keySet();
for(Object key:keySet){
Object value = prop.get(key);
System.out.println(key+value);
}
}
- setProperty(),设置集合的键和值,类型是String
- getProperty(),通过键搜索属性值
- stringPropertyNames(),返回一个不可修改的键集合,其中键及其值是字符串
多线程
进程
- 正在运行的程序,是系统进行资源分配和调用的独立单位
- 每一个进程都有它自己的内存空间和系统资源
线程
- 是进程中的单个顺序控制流,是一条执行路径
- 单线程:一个进程如果只有一条执行路径,则称为单线程程序
- 多线程:一个进程如果有多条执行路径,则称为多线程程序
方式一:继承 Thread 类实现多线程
//继承Thread
public class MyThread extends Thread {
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(i);
}
}
}
//实现
public static void main(String[] args) {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
//start():启动线程,由JVM调用此线程的run()方法
my1.start();
my2.start();
//run():未启动线程
// my1.run();
// my2.run();
}
设置和获取线程名称
- getName(): 获取线程名称
- public static Thread currentThread(): 获取当前正在执行的线程对象的引用
//MyThread类 继承 Thread类
public class MyThread extends Thread {
public MyThread() {
}
public MyThread(String name) {
super(name);
}
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(getName()+i);
}
}
}
//设置名称
public static void main(String[] args) {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
//MyThread my1 = new MyThread("高铁");
//MyThread my2 = new MyThread("飞机");
my1.setName("高铁");
my2.setName("飞机");
//启动线程,由JVM调用此线程的run()方法
my1.start();
my2.start();
//未启动线程
// my1.run();
// my2.run();
//获取当前正在执行的线程对象的引用
System.out.println(Thread.currentThread().getName());
}
线程调度
- public final int getPriority():返回此线程的优先级
- public final void setPriority(int newPriority): 更改此线程的优先级
public static void main(String[] args) {
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
//设置优先级,最大值为10,最小值为1,默认为5
my1.setPriority(10);
my2.setPriority(1);
//获取线程的优先级
System.out.println(my1.getPriority());
System.out.println(my2.getPriority());
//启动线程,由JVM调用此线程的run()方法
my1.start();
my2.start();
}
线程控制
- 线程休眠
public class MyThread extends Thread {
@Override
public void run() {
for(int i=0;i<100;i++){
System.out.println(getName()+i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
- 主线程结束后,若只剩下守护线程,那么守护线程也会很快停止。
public static void main(String[] args) {
Threadobj m1 = new Threadobj();
Threadobj m2 = new Threadobj();
m1.setName("高铁");
m2.setName("飞机");
//设置主线程
Thread.currentThread().setName("UFO");
//设置守护线程
m1.setDaemon(true);
m2.setDaemon(true);
m1.start();
m2.start();
for (int i=0;i<10;i++){
System.out.println(Thread.currentThread().getName()+":"+ i);
}
}
线程的生命周期
方式二:实现Runnable接口的方式实现多线程
- 好处:
- 避免了java单继承的局限性
- 适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好的体现了面向对象的设计思想
public static void main(String[] args) {
MyRunnable my = new MyRunnable();
Thread t1 = new Thread(my,"gay恒");
Thread t2 = new Thread(my,"胶恒");
t1.start();
t2.start();
}
线程同步-同步代码块-解决数据安全问题
- synchronized(任何对象){ 多条语句操作共享数据的代码 }
- 对象相同那么锁就相同,即同时生效
public class MyRunnable implements Runnable {
private Object obj = new Object();
@Override
public void run() {
synchronized (obj) {
for (int i = 0; i < 100; i++) {
System.out.println(Thread.currentThread().getName() + ":" + i);
}
}
}
}
同步方法
线程安全的类
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
Vector<String> v = new Vector<String>();
Hashtable<String,String> ht = new Hashtable<String,String>();
//下面这条代码等价=>Vector<String> v = new Vector<String>();
List<String> list = Collections.synchronizedList(new ArrayList<String>());
}
Lock锁
public class LockDemo implements Runnable {
private int tickets = 100;
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try {
lock.lock();
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "正在出售第" + tickets + "张票");
tickets--;
}
} finally {
lock.unlock();
}
}
}
}
生产者消费者模式
- 生产者线程用于生产数据,生产者生产数据后直接放置在共享数据区中,并不需要关心消费者的行为
- 消费者线程用于消费数据,消费者只需要从共享数据区中去获取数据,并不需要关心生产者的行为。
wait()、notify()
-
wait():导致当前线程等待,直到另一个线程调用该对象的notify()方法或者notifyAll()方法
-
notify():唤醒正在等待对象监视器的单个线程
-
notifyAll():唤醒正在等待对象监视器的所有线程
生产者消费者案例
- 牛奶案例
网络编程
-
计算机网络:指的是将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统
-
网络编程:在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换
三要素
- IP地址:每台计算机指定一个标识号
- 端口:应用程序的标识号
- 协议:在计算机网络中,连接和通信的规则称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。常见的协议有UDP协议和TCP协议
IP地址
-
常用命令
- ipconfig:查看本机IP地址
- ping IP地址:检查网络是否联通
-
127.0.0.1:是回送地址,可以代表本机地址,一般用来测试使用
InetAddress
public static void main(String[] args) throws UnknownHostException {
// InetAddress address = InetAddress.getByName("Lele");
InetAddress address = InetAddress.getByName(" 192.168.1.103");
String name = address.getHostName();
String ip = address.getHostAddress();
System.out.println(name + ":" + ip);
}
端口
- 端口号:用两个字节表示的整数,它的取值范围是0
65535.01023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号,如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。
协议
- UDP协议:用户数据报协议;无连接通信协议,数据的发送端和接收端不建立逻辑连接。UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输。
- TCP协议:传输控制协议;TCP协议是面向连接的通信协议
UDP通信
UDP发送数据
public static void main(String[] args) throws IOException {
//创建发送端的Socket对象(DatagramSocket)
DatagramSocket ds = new DatagramSocket();
//创建数据,并且报包
byte[] bys = "hello".getBytes();
// int length = bys.length;
// InetAddress address = InetAddress.getByName("192.168.1.103")
// int port = 10086;
// DatagramPacket dp = new DatagramPacket(bys,length,address,port)
DatagramPacket dp = new DatagramPacket(bys,bys.length,InetAddress.getByName("192.168.1.103"),10086);
//发送数据
ds.send(dp);
//关闭发送端
ds.close();
}
UDP接收数据
public static void main(String[] args) throws IOException {
//创建接收端的Socket对象
//DatagramSocket(int port)构造数据报套接字并将其绑定到本地主机上的指定端口
DatagramSocket ds = new DatagramSocket(10086);
//创建数据包,用于接收数据
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys, bys.length);
//调用DatagramSocket对象的方法接收数据
ds.receive(dp);
//解析数据包,并把数据在控制台显示
//byte[] getData() 返回数据缓冲区
byte[] datas = dp.getData();
//返回要发送的数据长度或接收到的数据的长度
int len = dp.getLength();
String dataString = new String(datas,0,len);
System.out.println(dataString);
ds.close();
}
TCP通信
TCP发送数据
public static void main(String[] args) throws IOException {
Socket s = new Socket("192.168.1.103",10000);
OutputStream os = s.getOutputStream();
os.write("hello".getBytes());
s.close();
}
TCP接收数据
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(10000);
Socket s = ss.accept();
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);
String data = new String(bys,0,len);
System.out.println("数据是,"+data);
s.close();
ss.close();
}
Lambda表达式
new Thread(() -> {
System.out.println("多线程程序启动了");
}).start();