JAVA 个人笔记

125 阅读27分钟

Java

常用DOS命令

操作说明
盘符名称:盘符切换。E:回车,表示切换到E盘。
dir查看当前路径下的内容
cd目录进入单级目录。cd itheima
cd ..回退到上一级目录
cd 目录1\目录2\ ..进入多级目录。cd itheima\JavaSE
cd \回退到盘符目录
cls清屏
exit退出命令提示符窗口

HelloWorld

  1. 建立 HelloWorld.java 文件

    public class HelloWorld {
    	public static void main(String[] args){
    		System.out.println("HelloWorld");
    	}		
    }
    
  2. 打开命令行窗口,cd进入HelloWorld.java 文件所在的目录

  3. 输入 javac HelloWorld.java

  4. 在输入 java HelloWorld.java

类型

  • 大致和c++一样

  • 注意:

    • long a = 10000L
    • float a = 3.14F
  • (等级最低)byte,short,char -> int -> long -> float -> double(等级最高)

    • 多个不同类型数运算,其结果的类型与参与运算的数钟最高级类型数相同

数据输入

  1. 导包

    import java.util.Scanner;
    // 导包的动作必须出现在类定义的上边
    
  2. 创建对象

    Scanner sc = new Scanner(System.in);
    // 上面这个格式里面,只有sc是变量名,可以变,其他的都不允许变
    
  3. 接收数据

    int i = sc.nextInt();
    // 上面这个格式里面,只有i是变量名,可以变,其他的都不允许变。
    

IDEA项目结构

  1. 创建一个空项目
  2. 创建一个新模块(idea_test)
  3. 在idea_test模块下的src下创建了一个包(com.itheima)
  4. 在com.itheima包下新建一个类(HelloWorld)
  5. 在HelloWorld类中编写代码
  6. 在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    
  • 关于权限问题

权限.png

_final

  1. 修饰方法:表明该方法是最终方法,不能被重写
  2. 修饰变量:表明该变量是常量,不能再次被赋值
  3. 修饰类:表明该类是最终类,不能被继承。
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 访问特点:

  • 非静态的成员方法

    1. 能访问静态的成员变量
    2. 能访问非静态的成员变量
    3. 能访问静态的成员方法
    4. 能访问非静态的成员方法
  • 静态的成员方法

    1. 能访问静态的成员变量
    2. 能访问静态的成员方法

多态(多态转型)

  • 成员变量:编译看父,执行看父

  • 成员方法:编译看父,执行看子

  • 多态中的转型

    • 向上转型

      • 从子到父

      • 父类引用指向子类对象

        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

异常

异常.png

  • 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)

  • 遍历:

    1. 因为List继承了Collection,所以可以通过迭代器

      Iterator<String> it = List.iterator();
      
    2. 通过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()

LinkedList.png

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.png

  • 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类判断及其获取功能

File.png

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);
        }
    }

线程的生命周期

线程的生命周期.png

方式二:实现Runnable接口的方式实现多线程

  • 好处
    1. 避免了java单继承的局限性
    2. 适合多个相同程序的代码去处理同一个资源的情况,把线程和程序的代码、数据有效分离,较好的体现了面向对象的设计思想
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);
            }
        }
    }
}

同步方法

同步方法.png

线程安全的类

线程安全的类.png

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():唤醒正在等待对象监视器的所有线程

生产者消费者案例

  • 牛奶案例

网络编程

  • 计算机网络:指的是将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信息传递的计算机系统

  • 网络编程:在网络通信协议下,实现网络互连的不同计算机上运行的程序间可以进行数据交换

三要素

  1. IP地址:每台计算机指定一个标识号
  2. 端口:应用程序的标识号
  3. 协议:在计算机网络中,连接和通信的规则称为网络通信协议,它对数据的传输格式、传输速率、传输步骤等做了统一规定,通信双方必须同时遵守才能完成数据交换。常见的协议有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);
    }

端口

  • 端口号:用两个字节表示的整数,它的取值范围是065535.01023之间的端口号用于一些知名的网络服务和应用,普通的应用程序需要使用1024以上的端口号,如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败。

协议

  • UDP协议:用户数据报协议;无连接通信协议,数据的发送端和接收端不建立逻辑连接。UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输

UDP.png

  • TCP协议:传输控制协议;TCP协议是面向连接的通信协议

TCP.png

UDP通信

UDP发送数据

UDP发送数据.png

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接收数据

UDP接收数据.png

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发送数据

TCP发送数据.png

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接收数据

TCP接收数据.png

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();