IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> java期末机考概要复习1.0 -> 正文阅读

[Java知识库]java期末机考概要复习1.0

这是一些java课堂笔记,主要是为了应付期末考试,随堂记,记得比较水,因为还没有开始复习所以与内容不是很契合考点,后续刷了题会进行相应更改。欢迎大家发现问题

Java课堂笔记

一、入门

1.1 Java概述

Java是一种高级计算机语言,sun公司推出的一种可以编写跨平台应用软件、完全面向对象的程序设计语言

JavaSE标准版 开发普通桌面程序和商务应用程序提供的解决方案
JavaEE企业版 为开发企业级应用程序提供的解决方案
JavaME微型版

1.2 JDK

JDK–java development kit Java的开发工具包(核心),提供了Java开发工具及运行环境和java基础类库;主要用于开发环境

JRE–java runtime enviroment java运行环境,提供了java的运行环境;编译器、调试器

JVM–java vritual Machine java虚拟机,java的运行时环境,主要用于解释class文件

jdk下目录:

bin:放一些可执行程序

include:放头文件

jre:java运行时环境的根目录

lib:类库

jdk、jre、jvm的关系?

jvm-Java Virtual Machine的缩写,就是Java虚拟机,它是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的,它使java语言在不同平台上运行时不用重复编译
jre -java Runtime Environment的缩写,java运行环境,jre内部有一个java虚拟机以及一些核心类库,就是辅助jvm运行的文件,jre是运行java字节码文件的 必备工具
jdk-java development kit,java开发工具集,它提供了java开发,编译以及运行所需要的文件和环境,它包含jre和java开发工具

java是如何实现跨平台的?

跨平台就是指java能在不同的环境主要是不同的操作系统下运行,java代码运行时会将java文件编译成字节码文件,然后使用jvm运行字节码文件,java的开发团队在不同的平台开发出了不同的java虚拟机版本,这使得同一个java代码文件可以在不同的平台上运行。

1.3 cmd运行java代码

创建java代码文件——打开cmd进入java文件所在位置——运行javac X.java ——运行java X

1.4 Java运行机制

编写java程序——编译器编译成.class文件——类加载器将字节码文件加载到内存——JVM对字节码文件进行解释运行

二、Java编程基础

2.1 JAVA基本语法

  1. 标识符:数字字母下划线+$,数字不能开头

  2. 结构定义语句声明类或方法,用于实现具体的功能
    功能执行语句必须与英文逗号结尾

2.2 变量的数据类型

数据类型:规定了数据所占字节数、数据范围、数据可以进行的操作

1、基本数据类型

  • 整型
    • byte 8位 1个字节 - 128~127(7次方)
    • short 16位 2个字节 3万(15次方)
    • int 32位 4个字节 21亿(31次方)
    • long 64位 8个字节 63次方
  • 浮点型(在内存中不能准确存储)
    • float 32位 4个字节 7位有效数字
    • double 64位 8个字节 15位有效数字
  • 字符型 char 2个字节 0-65535
  • 布尔型

2、引用数据类型

  • 接口
  • 数组
  • 枚举
  • 注解

2.3 数据类型转换

强制类型转换
自动类型转换取值范围小的——>取值范围大的

byte《 short/char 《 int 《 long《 float《 double

2.4 运算符

异或:不同才是真的,相同是假的

? 运算规则:与0异或不变、与1异或变反、与自己异或清零、相反异或置1

? 使用异或交换变量值

? a=a^b;

? b=a^b;//a^b^b

? a=a^b;//a^b^a

赋值运算符:强制类型转换会自动完成

? short s=3;

? int i=5;

? s+=i; //不需要手动类型转换

? java中可以通过一条赋值语句给多个变量赋值 a=b=c=2;

位运算符:

? a<<b://a=a*2^b 二进制右边加b个0

? a>>b://a=a/2^b 二进制左边加b个0或1

? a>>>b://s二进制左边加b个0

i++与++i效率问题

a=i++; 先将用一个临时变量存i的值,再运算i=i+1;,再将临时变量的值赋给a;

a=++i; ,再i=i+1,将i的值赋给a;

++i的效率更高

2.5数组

数组定义

静态初始化:
int[] arr={1,2,3,4};
{}只能用在定义的这一句
动态初始化:
int[] arr=new int[size];
int[] arr=new int[]{1,2,3,4};

内存分析

栈区:存放方法

堆区:new的对象

方法区:

栈中存放地址,堆中存放数据

数组的长度不能改变,因为数组在内存中是一块连续的内存空间,想增加元素时,不确定后一块内存是否有别的进程在使用

String

toStirng()

intern

.equals()属性值相等,需要重写(String中重写了)
== 属性值相等,内存里的位置必须也是同一个
String是一个被final修饰的类,不可修改
String s1=“hello” s1:栈 指向方法区的常量池
String s2=“world”
String s3=s1+s2; s3:栈 指向堆
String s4=s1+“world"
Stirng s5=”hello"+“world” s5:栈 指向方法区

==与.eqluas区别?

三、面向对象(封装、继承、多态)

3.1 访问修饰符

在这里插入图片描述

外部类的可见性:只能有两种访问控制级别,public和default

3.2 封装

重载

重载:一个函数中定义多个参数列表不同的构造函数,jvm通过参数列表的不同决定执行哪一个构造函数。与返回值类型、访问权限无关

this

this.属性:表示当前的对象的属性(成员变量),是一个引用

this.方法:调用当前对象的其他方法

this(参数列表):调用其他的构造方法,必须写在该构造函数的第一行

如果类的属性是一个有效的赋值语句,那么创建对象时会先执行对类对象的赋值,再调用构造函数

static

修饰类(静态内部类)和属性,实现类的静态方法和静态属性的共享

随着类的加载保存在方法区,生命周期与类相同
静态方法中只能访问静态的变量和方法

jvm的类加载过程(classloder)——懒加载

1)加载:加载class文件到jvm

2)验证:验证文件格式、元数据、字节码等

3)准备:为静态变量分配内存,并赋初值(如果被final修饰则在编译时会给属性加上ConstantValue属性,准备阶段直接完成赋值操作)

4)解析:将常量池中的符号引用转为直接引用

5)初始化:执行静态代码块,完成静态变量的赋值。静态字段、静态代码段,字节码层面会生成clinit方法。clinit方法中语句的先后顺序与代码的编写顺序相关

类的初始化顺序

p.静态变量,p.静态代码块
c.静态变量,c.静态代码块
p.普通成员变量,p.普通代码块,p.构造方法(构造方法不能被继承)
c.普通成员变量,c.普通代码块,c.构造方法

3.3 继承 extends

java 支持类的单继承,接口的多继承,只能继承父类的非私有属性和方法

实现父子关系,以及代码的复用

构造函数不能继承,但是可以通过super关键字调用

重写 @Override

基于继承关系,子类对父类已经存在的方法进行覆盖重写
两个方法的名称参数列表必须相同
子类中重写方法的返回值类型必须是父类中方法的返回值类型或者该类型的子类,不能返回比父类更大范围的数据类型;
子类中的重写方法不能比父类中被重写的方法产生更多的异常

子类重写的方法访问权限大于等于父类方法的

重写的条件是两同两小一大

final

final是使中的内容不改变
修饰类:该类不会有继承的子类
修饰成员属性:
1.变量,定义常量(必须在声明时、或者代码块、或者构造方法中初始化)
2.基本数据类型,值不变
3.引用类型,对象引用不变,对象的内容可变
修饰局部变量:表示常量,只能在定义时进行初始化
修饰方法:该方法不会被子类继承并重写
修饰形参:该形参在所属方法中不能被修改

super

对当前对象的父类对象的引用,用于访问父类的属性,父类的方法和父类的构造方法。
super和this很像,this方法调用其他构造函数必须是该构造函数的第一个有效语句,super也是,所以这两个不能在这种情况一起使用

3.4 abstract类与接口interface

抽象类中不一定只有抽象方法,只能通过子类创建实例

抽象方法只有方法声明,没有方法体。必须在抽象类或接口中定义

接口中的方法默认为 public abstract(jdk1.8以后默认方法使用default修饰,静态方法使用static修饰,这两种方法可以有方法体)

接口中的属性默认为 public static final

接口是特殊的抽象类,只包含常量和抽象方法

抽象类是对属性的抽象,接口是对方法的抽象;大量的继承会使代码耦合度变高,好的代码应满足高内聚低耦合,尽量面向接口编程

3.5 多态

条件:

? 继承与重写

? 父类引用指向子类对象(上转型对象)

? Person p1=new Person();//父类对象
? Student s1=new Student();//子类对象
? Person p2=new Student();//父类引用指向子类
? p1.eat();//父类的非静态方法
? s1.eat();//子类的非静态方法

? /*

? 非静态方法编译看左边(编译时创建左边类的对象
? 运行看右边(运行时调用右边类的方法)

? */
? p2.eat();//子类的非静态方法

多态:`Percent p = new Children();
对于成员方法:编译看左边,运行看右边。
对于成员变量:编译运行都看左边。也就是成员变量没有多态特性。
静态方法和变量:编译运行都看左边,同成员变量一样。

3.6 内部类

  1. 成员内部类

    成员内部类中可以访问外部类中的所有成员,反之也是

    外部类名.内部类名 变量名=new 外部类名().new 内部类名();

  2. 局部内部类

    局部内部类中可以访问外部类中的所有成员,而局部内部类中的成员只能在该类创建的方法中进行访问

    通过调用局部内部类所在方法来调用内部类

  3. 静态内部类

    static修饰的成员内部类

    静态内部类只能访问外部类的静态成员,外部类访问静态内部类时,可以跳过外部类而直接通过内部类访问静态内部类成员

    外部类名.静态内部类名 变量名=new 外部类名.静态内部类名();

  4. 匿名内部类

    =new 父类或接口(){
    执行代码
    };

Lambda表达式—基于函数式接口

表达一个接口实现类的对象(只针对含有一个抽象方法的接口实现),简化了对集合以及数组数据的遍历、过滤和提取等操作

([数据类型 参数名,数据类型 参数名...]) -> (表达式主体) 参数传给方法体

(参数)-> {执行代码};

函数式接口 只含有一个抽象方法的接口

@Functionallnterface注解 确保改接口是函数式接口

当表达式主体只有一条语句时,程序可以省略包含主体的大括号,可以通过英文::来引用方法和构造器

3.7 异常

自定义异常类必须继承Exception
在这里插入图片描述

1)ERROR

Error一般不能处理(修改代码不能解决),由java虚拟机抛出,比如 OutofMemory(OOM),StackOverflowError

2)Exception(运行阶段)

受检异常(编译时异常),使用到外部资源,外部资源出了问题 如 IOException 必须在代码中对编译时异常进行处理
RuntimeException(运行时异常)可处理可不处理(提高程序健壮性)如 下标越界异常

3)编译时异常处理方法

(1)try…catch

? 自上而下的顺序,注意父类型异常必须写在子类型异常的下面,不然会捕捉不到子类型异常。另外,即便搭配了多个catch,意思是可以捕获多种类型异常中的一个,不能捕捉多个异常,因为一旦try中发生异常,那么try中发生异常后面的代码就不会继续执行加了。(jdk8的新特性:一个catch里可以捕捉多种类型的异常,在catch中用“|”分开)

? 异常抛出后try…catch的代码仍会执行。。。多线程?

(2)throws往上一级抛异常

4)throw和throws 的区别

? throw是用在方法体上,抛出一个具体的异常对象。如果Throw抛出的异常是ERROR、RuntimeException异常对象,则无需使用Throws或者try…catch对异常进行处理=

? 而throws是用类方法声明上,抛出的是异常类型,这个类型表明了,我们在上级对这个异常进行处理的时候,是针对这个异常的类型而言的:比如某个方法存在一个IOException,那么我们在抛出或者try……catch的时候,就只能是针对这个IOException或者它的父类而言。其实这也多态的一种体现,抛出的某个类型的对象,我们用它的父类来接收。

5)finally与return

结论1

? finally比return的权力更大,同时存在finally和return时,finally还是会执行

结论2

? 如果finally中没有return,那么会在执行了finally之后,将前面的return返回;如果finally中对前面返回的那个值进行了修改,返回的值是不会受finally中代码的影响的,因为前面被返回的值已经被存入了一个临时变量中,finally执行完毕,返回的也是那个临时变量。如果前面和finally中都使用return返回了一个变量,那么finally中的那个会覆盖之前的。

3.8 常用类

四、集合

这里有以前的笔记:

https://blog.csdn.net/qq_44768955/article/details/107684335

?

五、I/O流

输入输出以内存为参照

File

用于封装一个路径(绝对路径、相对路径),封装路径可以指向一个目录,也可以指向一个目录 “D:\\abc.txt” || “D:/abc.txt”

 /*遍历目录文件及其子文件*/
 public static void printFile(File dir){
        //获取文件夹下所有的文件和文件对象
        File[] files = dir.listFiles();
        for (File file: files) {
            if (file.isFile()){
                System.out.println(file.getName());
            }else if (file.isDirectory() && file.listFiles()!=null){
                printFile(file);
            }
        }
    }

字节流(适用于非纯文本文件)

? InputStream、OutputStream

        FileInputStream fileInputStream=null;
        FileOutputStream fileOutputStream=null;

        byte[] bytes= new byte[1024];
        int len;

        try {
            fileInputStream=new FileInputStream("D:\\abc.txt");
            fileOutputStream=new FileOutputStream("D:\\a.txt",true);
            while ((len=fileInputStream.read(bytes)) !=-1){
                fileOutputStream.write(bytes);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (fileInputStream!=null){
                try {
                    fileInputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fileOutputStream!=null){
                try {
                    fileOutputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

? 缓冲字节流(内置两个数组作为缓冲区)

 BufferedInputStream inputStream=null;
        BufferedOutputStream outputStream=null;
        int i;
        try {
            inputStream = new BufferedInputStream(new FileInputStream(""));
            outputStream = new BufferedOutputStream(new FileOutputStream(""));
            while ((i=inputStream.read())!=-1){
                outputStream.write(i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (inputStream!=null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (outputStream!=null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

缓冲字节流的效率没有自定义一个数组作为缓冲区的InputStream、OutputStream高

缓冲字节流中:字节数组1—>应用程序—>字节数组2

字符流(解决字节流操作中文乱码问题,只能操作纯文本文件)

字符流底层是通过字节流+编码表的形式进行读取,读取中文时,会根据平台默认编码表决定一次读取多少字节,并在内存中转换为字符,读非中文时就一个一个读,其实每次都会先读一个,如果是负数则说明是中文(一般是负数),在重新读n个

中文: GBK—>两个字节、UTF-8—>三个字节

? Reader、Writer

/**
         * FileWriter的flush和close方法的区别:
         *  flush:将数据刷到文件中去。刷出之后可以继续用write方法写出
         *  close只要是关闭释放资源,同时具有刷出数据的效果
         */
        FileReader fileReader=null;
        FileWriter fileWriter=null;
        char[] chars=new char[1024];
        int i;
        try {
            fileReader=new FileReader("D:/abc.txt");
            fileWriter=new FileWriter("D:/a.txt");
            while ((i=fileReader.read(chars))!=-1){
                fileWriter.write(chars,0,i);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(fileReader!=null){
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(fileWriter!=null){
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

? 缓冲字符流

  BufferedReader bufferedReader=null;
        BufferedWriter bufferedWriter=null;
        String line;
        try {
            bufferedReader=new BufferedReader(new FileReader(""));
            bufferedWriter=new BufferedWriter(new FileWriter(""));
            while ((line=bufferedReader.readLine())!=null){//一次读一行,不会取到回车换行符
                bufferedWriter.write(line);
                bufferedWriter.newLine();//写出回车换行,可跨平台
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if(bufferedReader!=null){
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(bufferedWriter!=null){
                try {
                    bufferedWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

转换流

可以按照指定的编码表写数据

  		//按指定编码表读取数据
        InputStreamReader inputStreamRreader=new InputStreamReader(new FileInputStream("D:/abc.txt"),"utf-8");
        //按指定编码表写数据
        OutputStreamWriter outputStreamWriter=new OutputStreamWriter(new FileOutputStream(""),"utf-8");

        BufferedReader bufferedReader=new BufferedReader(inputStreamRreader);
        BufferedWriter bufferedWriter=new BufferedWriter(outputStreamWriter);

其它流

? 序列流(sequenctInputStream)
? 序列化与反序列化
? 打印流
? 随机访问流
? Prperties

六、多线程

进程、线程、程序

进程是一个正在运行的程序,(多)线程是程序的一(多)条执行路径

程序就是硬盘上的一堆代码,程序进入内存运行就变成了一个进程,进程中可以包含多个线程,线程是程序执行的一条路径

多线程:多条执行路径在同时执行。充分利用cpu资源,进一步提升程序执行效率。

线程的创建

继承Thread

public class Demo01 {
    public static void main(String[] args) {
        //3、创建对象并设置线程名
        MyThread01 myThread=new MyThread01("MyThread");
        //4、开启线程
        myThread.start();
        //设置当前线程的线程名3
        Thread.currentThread().setName("主线程");
        while (true){
            //获取当前线程的名称
            System.out.println(Thread.currentThread().getName());
        }
    }
}
//1、继承Thread类
class MyThread01 extends Thread{
    //设置线程名方法2
    MyThread01(String string){
        super(string);
    }

    //2、重写run方法
    @Override
    public void run(){
        //设置线程名方法1
//        setName("MyThread");
       while (true){
           //打印线程名
            System.out.println(getName());
        }
    }
}

实现Runnable

public class Demo02 {
    public static void main(String[] args) {
        //3、创建对象
        MyThread02 myThread02=new MyThread02();
        //4、将实现类对象作为资源传递给Thread类的有参构造,并调用start方法开启线程
        new Thread(myThread02).start();

        while (true){
            System.out.println(Thread.currentThread().getName());
        }
    }
}
//1、实现Runnable接口
class MyThread02 implements Runnable{
    //2、重写run方法
    @Override
    public void run() {
        while (true){
            System.out.println(getName());
        }
    }
}

实现Callable

public class Demo03 {
    /**
     * 既能开启线程又能得到线程的返回值结果
     * @param args
     */

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //2、创建FutureTask对象,并将MyThread03实现对象传入构造方法
        FutureTask<Integer> fk1=new FutureTask<>(new MyThread03());
        //3、将FutureTask实现类对象作为资源传递给Thread类的有参构造,并调用start方法开启线程
        new Thread(fk1,"线程A").start();

        FutureTask<Integer> fk2=new FutureTask<>(new MyThread03());
        new Thread(fk2,"线程B").start();

        System.out.println(fk1.get());
        System.out.println(fk2.get());

    }
}
//1、实现Callable接口
class MyThread03 implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"当前"+i++);
            sum+=i;
        }
        return sum;
    }
}

三种方法的区别

实现Runnable,适合多个线程处理同一个共享资源的情况;可以避免java单继承带来的问题

public class Demo03 {
    /**
     * 实现Callable接口创建线程的方法,既能开启线程又能得到线程的返回值结果
     * @param args
     */

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        //2、创建FutureTask对象,并将MyThread03实现对象传入构造方法
        FutureTask<Integer> fk1=new FutureTask<>(new MyThread03());
        //3、将FutureTask实现类对象作为资源传递给Thread类的有参构造,并调用start方法开启线程
        new Thread(fk1,"线程A").start();

        FutureTask<Integer> fk2=new FutureTask<>(new MyThread03());
        new Thread(fk2,"线程B").start();

        System.out.println(fk1.get());
        System.out.println(fk2.get());

    }
}
//1、实现Callable接口
class MyThread03 implements Callable<Integer>{

    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName()+"当前"+i++);
            sum+=i;
        }
        return sum;
    }
}
public class Test01 {
    public static void main(String[] args) {
        MyTicketsRunnable myTicketsRunnable1=new MyTicketsRunnable();
        new Thread(myTicketsRunnable1,"窗口1").start();
        new Thread(myTicketsRunnable1,"窗口2").start();
    }
}
class MyTicketsRunnable implements Runnable{
    int ticket=10;
    @Override
    public void run() {
        while (true){
            if (ticket<=0) break;
            System.out.println(Thread.currentThread().getName()+"卖出了第"+(ticket--)+"张票");
        }
    }
}
public class Test01 {

    public static void main(String[] args) {
        MyTicketsRunnable myTicketsRunnable1=new MyTicketsRunnable();
        new Thread(myTicketsRunnable1,"窗口1").start();
        MyTicketsRunnable myTicketsRunnable2=new MyTicketsRunnable();
        new Thread(myTicketsRunnable2,"窗口2").start();
    }
}
class MyTicketsRunnable implements Runnable{
    static int ticket=10;
    @Override
    public void run() {
        while (true){
            if (ticket<=0) break;
            System.out.println(Thread.currentThread().getName()+"卖出了第"+(ticket--)+"张票");
        }
    }
}

关于这个多线程售票的案例有另一个博客进行详细说明 多线程安全经典案例:多窗口售票

守护线程

new Thread(true) 将该线程设置为守护线程

当非守护线程执行完成,守护线程(后台线程)也结束;

只要有一个前台线程在运行,这个进程就不会结束;只有后台线程在运行,这个进程就会结合素

线程优先级

优先级1-10,默认为5.优先级高的执行概率高

new Thread().setPriority(int priority);

线程生命周期

在这里插入图片描述

new -新建 调用start方法后进入runnable状态

Runnable --等待被cpu调度 不能直接进入Blocked 状态和Terminated 状态(没有)

Running --正在运行 stop() ->Terminated状态

? io阻塞、获取同步锁的释放->Blocked 状态

? 时间片用完、yeild() -> Runnable 状态

? wait(无参),join(无参) ->waiting状态

? wait(有参),join(有参) ->timed_waiting状态

Wating --等待

Timed_Wating --计时等待

Blocked --阻塞

Terminated --结束

注:使用wait()后必须等待其他线程盗用notify()或notifyAll()才能唤醒当前等待中 的线程

线程让步

Thread.yield() 线程运行到此,做出让步,让cpu重新选择,可能还是自己抢到

线程休眠

Thread.sleep()

线程插队

new thread().join(long millis) 让调用此方法的对象立即执行,等待该线程终止后(等待执行millis毫秒后)原本执行的线程再执行

线程同步

同步代码块

//mutex锁对象,可以是任意对象,但同步的线程的锁对象必须是同一个锁
synchronized (mutex){	}

同步方法

//默认锁对象是this指向的对象
//静态方法中的锁是该方法所在类的class对象

同步锁

//持续获取一个资源失败后直接让其返回,不会继续等待
Lock lock=new ReentrantLock();
lock.lock();
lock.unlock();

死锁问题

互相等待,尽量避免嵌套使用同步锁

多线程通信

wait()和notify()实现,谁是锁对象,就得用谁进行调用

1,线程同步

2.设置标志变量flag

3.通过判断标志变量的值,决定执行哪个线程

4.通过wait()让当前线程等待

5,通过notify()唤醒等待的另外一个线程

辨析wait()和sleep() : 一个释放锁一个不释放锁

七、GUI图形用户界面

Swing概述

AWT(抽象窗口工具包):统一不同操作系统的图形界面,但是有不兼容问题

Swing:是以AWT为基础的轻量级组件

两个分支容器分支(Windows窗口和Panel面板)、组件分支(向容器中填充数据)

常用的容器:JFrame、JDialog

JFrame(顶级容器-不能放在其他窗体之中)

public static void main(String[] args) {
        //更安全,主线程不能更新UI
        SwingUtilities.invokeLater(() -> forms());
    }

    public static void forms() {
        JFrame jf=new JFrame("窗体一");
        //设置窗体可见
        jf.setVisible(true);
        //设置窗体标题
        jf.setTitle("窗体二");
        //设置关闭窗体程序也关闭
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        //设置窗体大小
        jf.setSize(500,500);
        //设置窗体位置
        jf.setLocation(200,200);
        //设置窗体大小和位置
        //jf.setBounds(100,200,300,400);
    }

JDialog(依附于JFrame)

模态对话框:该窗口弹出后其他窗口不能操作

非模态对话框:该窗口弹出后其他窗口能操作

 //创建Dialog对话框,名为a,设置为模态对话框(默认为非模态)
        JDialog dialog=new JDialog(jf,"a",true);
        dialog.setVisible(true);
        dialog.setDefaultCloseOperation(JDialog.HIDE_ON_CLOSE);
        dialog.setSize(300,300);

布局管理器

Swing组件必须放在容器中,组件的位置和尺寸由布局管理器决定

BorderLayout边界布局管理器

改变窗体大小时,组件的相对位置不改变。每个区域只能放一个组件,放多个时后放的为准。

在这里插入图片描述

	//指定布局-边界布局
        jf.setLayout(new BorderLayout());
        //创建五个组件
        JButton btn_1=new JButton("页头pager_start");
        JButton btn_2=new JButton("页尾pager_end");
        JButton btn_3=new JButton("行头line_start");
        JButton btn_4=new JButton("行尾pager_start");
        JButton btn_5=new JButton("中部center");
        //将组建添加到容器,并指定位置
        jf.add(btn_1,BorderLayout.PAGE_START);
        jf.add(btn_2,BorderLayout.PAGE_END);
        jf.add(btn_3,BorderLayout.LINE_START);
        jf.add(btn_4,BorderLayout.LINE_END);
        jf.add(btn_5,BorderLayout.CENTER);

FlowLayout流式布局管理器

组件会按照添加顺序从左往右放置,改变窗体大小组件的相对位置会改变

 		//指定流式布局,可通过构造方法指定组件的相对位置(左对齐右对齐等) CENTER水平垂直间距
        jf.setLayout(new FlowLayout(FlowLayout.CENTER,10,10));
        //设置并添加按钮组件
        jf.add(new JButton("按钮一"));

GridLayout 网格布局管理器

使用纵横线将窗体分隔成n行m列个大小相等的网格,在每个网格中添加一个组件,每个组件会占满整个小网格。改变窗体大小时网格大小改变,组件的数量不会改变,所有组件的宽高都相同。

//指定网格布局
        jf.setLayout(new GridLayout(3,4));
        //设置并添加按钮组件
        for (int i = 0; i < 12; i++) {
            JButton btn=new JButton("btn");
            jf.add(btn);
        }

空布局

自己设定每个组件的高度和宽度,比较常用;
自打做了实验,这个是真的恼火,比c3还烦,后面还要做课设。。┭┮﹏┭┮

事件处理机制

用于响应用户的操作

事件源:事件发生的场所,事件的组件

事件对象:封装了GUI组件上发生的特定事件,封装了当前事件相关的一切信息(包括事件源)

监听器:监听事件源上发生的事件,并对事件做出相应的处理,事件处理方法

处理流程:

1、将监听器注册到事件源

2、触发事件源上的监听器

3、产生并传递事件对象

4、接收事件对象,激活事件处理器,实现预定功能

//创建按钮组件-事件源
        JButton btn = new JButton("按钮");
        //为事件源注册监听器 ActionListener监听动作时间
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("触发了监听器");
            }
        });
        //添加组件到窗体
        jf.add(btn);

窗体事件

//为窗体注册监听器
        jf.addWindowListener(new WindowListener() {
            @Override
            public void windowOpened(WindowEvent e) {
                System.out.println("windowOpened---窗体打开时触发");
            }

            @Override
            public void windowClosing(WindowEvent e) {
                System.out.println("windowClosing---窗体正在关闭事件");
            }

            @Override
            public void windowClosed(WindowEvent e) {
                System.out.println("windowClosed---窗体已经关闭事件");
            }

            @Override
            public void windowIconified(WindowEvent e) {
                System.out.println("windowIconified---窗体停用事件");
            }

            @Override
            public void windowDeiconified(WindowEvent e) {
                System.out.println("windowDeiconified---取消窗体图标化事件(取消最小化)");
            }

            @Override
            public void windowActivated(WindowEvent e) {
                System.out.println("windowActivated---窗体激活事件(鼠标焦点进入)");
            }

            @Override
            public void windowDeactivated(WindowEvent e) {
                System.out.println("windowDeactivated---窗体停用事件(鼠标焦点离开)");
            }
        });

鼠标事件

//创建按钮组件-事件源
        JButton btn = new JButton("按钮");
        //为事件源注册监听器
        btn.addMouseListener(new MouseListener() {
            @Override
            public void mouseClicked(MouseEvent e) {
                System.out.println("mouseClicked---鼠标完成单击事件");
            }

            @Override
            public void mousePressed(MouseEvent e) {
                System.out.println("mousePressed---鼠标按下事件");
                int button = e.getButton();
                if (button==MouseEvent.BUTTON1){
                    System.out.println("鼠标左击了");
                }else if(button==MouseEvent.BUTTON2){
                    System.out.println("鼠标滚轮了");
                }else {
                    System.out.println("鼠标右击了");
                }
            }

            @Override
            public void mouseReleased(MouseEvent e) {
                System.out.println("mouseReleased---鼠标放开事件");
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                System.out.println("mouseEntered---鼠标进入按钮区域事件");
            }

            @Override
            public void mouseExited(MouseEvent e) {
                System.out.println("mouseExited---鼠标移出按钮区域事件");
            }
        });
        //添加组件到窗体
        jf.add(btn);

键盘事件

//创建文本输入框组件-事件源 按钮也可以用
        JTextField text =new JTextField(10);

        text.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //通过getKeychar()获取键盘按下的字符
                char keyChar = e.getKeyChar();
                //通过getKeychar()获取键盘按下的字符代码
                int keyCode = e.getKeyCode();
                System.out.println("字符为"+keyChar+",字符代码为"+keyCode);
            }
        });
        jf.add(text);

ActionListener动作事件

适配器设计模式

当需要使用接口中部分功能时,可以考虑设计一个适配器,这样就不用重写所有的抽象方法了。这里摸鱼去了事后想起来感觉模棱两可的,等复习的时候再瞅瞅

//事件源对象.需要监听事件监听器类(new 接收所需事件的抽象适配器类(){重写需要监听的方法}) 例如:
		text.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                //通过getKeychar()获取键盘按下的字符
                char keyChar = e.getKeyChar();
                //通过getKeychar()获取键盘按下的字符代码
                int keyCode = e.getKeyCode();
                System.out.println("字符为"+keyChar+",字符代码为"+keyCode);
            }
        });

常用组件

面板组件

中间容器,只能放在顶级容器中

JScrollPanne 有滚动条

Jpanel 无滚动条

//创建带有滚动条的面板组件
        JScrollPane jScrollPane=new JScrollPane();
        //设置水平滚动策略,当组件超过窗体大小才显示滚动条
        jScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        //设置垂直滚动  滚动条一直存在
        jScrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        //创建JPanel ,存贮多个组件
        JPanel jPanel=new JPanel();
        jPanel.add(new JButton("按钮1"));
        jPanel.add(new JButton("按钮2"));
        jPanel.add(new JButton("按钮3"));
        jPanel.add(new JButton("按钮4"));
        //将组织好的Jpanel组件放入jScrollPane中
        jScrollPane.setViewportView(jPanel);
        //将JScrollPane组件放入主窗体
        jf.add(jScrollPane);

文本组件

用于接收用户输入的信息

文本框 JTextFiled 只能接受一行数据

文本域 JTextArea 可以接收多行数据

实现案例1:

在这里插入图片描述

public class Test01 {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(()->createForms());
    }
    public static void createForms(){
        JFrame jf=new JFrame("案例1");
        jf.setBounds(100,200,300,400);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);
        //设置边界布局
        jf.setLayout(new BorderLayout());
        //创建聊天记录的文本域
        JTextArea jTextArea=new JTextArea(12,25);
        //设置其不可编辑
        jTextArea.setEditable(false);

        //创建滚动条面板组件,将文本域放进去
        JScrollPane jScrollPane=new JScrollPane(jTextArea);

        jf.add(jScrollPane,BorderLayout.PAGE_START);
        //创建文本输入框、发送按钮
        JTextField jTextField=new JTextField(10);
        JButton btn=new JButton("发送");
        //给按钮注册监听事件
        btn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                //获取文本框中的数据
                String text = jTextField.getText();
                if (text !=null && !text.equals("")){
                    //将输入的数据发送到文本域
                    jTextArea.append("本人输入信息为:"+text+"\n");
                    //清空文本框中的数据
                    jTextField.setText("");
                }else {
                    jTextArea.append("-------发送内容不能为空------\n");
                }

            }
        });
        //创建提示标签
        JLabel jLabel=new JLabel("聊天信息");

        JPanel jPanel=new JPanel();
        jPanel.add(jLabel);
        jPanel.add(jTextField);
        jPanel.add(btn);
        jf.add(jPanel,BorderLayout.PAGE_END);
    }
}

标签组件

用于显示图片或者文本

//设置边界布局
        jf.setLayout(new BorderLayout());
        //创建图片JLabel
        JLabel label=new JLabel();
        ImageIcon icon=new ImageIcon("D:\\idea2018\\javaeeTest\\2.jpg");
        //修改图片尺寸
        Image image = icon.getImage();
        image=image.getScaledInstance(300,250,Image.SCALE_DEFAULT);
        icon.setImage(image);

        label.setIcon(icon);

        //创建图片JLabel
        JLabel jLabel1=new JLabel("欢迎进入猫猫超市");

        jf.add(jLabel1,BorderLayout.PAGE_END);
        jf.add(label,BorderLayout.PAGE_START);

实验的两个小案例我也放在这里吧
在这里插入图片描述

package test10;

import javax.swing.*;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

/**
 * @User yang
 * @date 2021/12/13 14:08
 */
public class Demo01 {
    public static void main(String[] args) {
        //更安全,主线程不能更新UI
        SwingUtilities.invokeLater(() -> forms());
    }

    public static void forms() {
        JFrame jf=new JFrame("小朋友练口算");
        jf.setSize(400,300);
        jf.setLocationRelativeTo(null);
        Random random=new Random();

        JLabel op1Label=new JLabel("5");
        JLabel op2Label=new JLabel("6");
        JLabel opLabel=new JLabel("+");
        JLabel eqLabel=new JLabel("=");

        JMenuBar menuBar=new JMenuBar();
        JMenu yunsMenu = new JMenu("运算种类");
        JMenuItem addItem = new JMenuItem("加法");
        addItem.addActionListener(e->opLabel.setText("+"));
        JMenuItem multItem = new JMenuItem("乘法");
        multItem.addActionListener(e->opLabel.setText("*"));
        yunsMenu.add(addItem);
        yunsMenu.add(multItem);
        menuBar.add(yunsMenu);
        jf.setJMenuBar(menuBar);

        JLabel resultLabel = new JLabel("    ");
        resultLabel.setBackground(Color.YELLOW);
        resultLabel.setOpaque(true);
        jf.add(resultLabel,BorderLayout.PAGE_END);

        JTextField jtfResult = new JTextField("   ");
        jtfResult.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int op1=Integer.parseInt(op1Label.getText());
                int op2 = Integer.parseInt(op2Label.getText());
                int result = Integer.parseInt(jtfResult.getText().trim());
                if ("+".equals(opLabel.getText())){
                    if (result==op1+op2){
                        resultLabel.setText(op1+"+"+op2+"="+result+"恭喜你答对啦");
                    }else {
                        resultLabel.setText(op1+"+"+op2+"="+result+"很遗憾你答错了");
                    }
                }else{
                    if (result==op1*op2){
                        resultLabel.setText(op1+"*"+op2+"="+result+"恭喜你答对啦");
                    }else {
                        resultLabel.setText(op1+"*"+op2+"="+result+"很遗憾你答错了");
                    }
                }
                op1Label.setText(""+random.nextInt(9));
                op2Label.setText(""+random.nextInt(9));
                jtfResult.setText("    ");
            }
        });
        JPanel jp =new JPanel();
        jp.setBackground(Color.GREEN);
        jp.add(op1Label);
        jp.add(opLabel);
        jp.add(op2Label);
        jp.add(eqLabel);
        jp.add(jtfResult);
        jf.add(jp,BorderLayout.PAGE_START);
        jf.add(resultLabel);
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);




    }
}

在这里插入图片描述

package test10;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;

/**
 * @User yang
 * @date 2021/12/13 14:48
 */
public class Demo02 {
    public static void main(String[] args) {
        //更安全,主线程不能更新UI
        SwingUtilities.invokeLater(() -> forms());
    }

    public static void forms() {
        JFrame jf = new JFrame();
        jf.setSize(800, 600);
        jf.setLocationRelativeTo(null);

        JTextField jtf=new JTextField("  ");
        ///
        jf.add(jtf,BorderLayout.PAGE_END);

        JPanel jp = new JPanel();
        jp.setLayout(null);
        jp.setBackground(Color.LIGHT_GRAY);
        jf.add(jp);

        jtf.addActionListener(new jtfActionListener(jtf,jp));
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        jf.setVisible(true);
    }
}
class jtfActionListener implements ActionListener{
    JTextField jtf;
    JPanel jp;

    public jtfActionListener(JTextField jtf, JPanel jp) {
        super();
        this.jtf = jtf;
        this.jp = jp;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        new Thread(new DanmuJlb(jtf,jp)).start();
    }


}
class DanmuJlb implements Runnable {
    JTextField jtf;
    JPanel jp;
    private static Color[] color={Color.RED,Color.BLUE,Color.CYAN,Color.GREEN
    ,Color.ORANGE,Color.MAGENTA,Color.PINK,Color.YELLOW,Color.BLACK};
    private static Color getC(){
        return color[new Random().nextInt(color.length)];
    }
    public DanmuJlb(JTextField jtf, JPanel jp) {
        this.jtf = jtf;
        this.jp = jp;
    }
    @Override
    public void run() {
        String str=jtf.getText();
        Font font=new Font("宋体",Font.BOLD,new Random().nextInt(30)+20);
        JLabel jlb = new JLabel(str);
        jlb.setForeground(this.getC());
        jlb.setAlignmentY(JLabel.TOP_ALIGNMENT);
        jlb.setFont(font);
        jp.add(jlb);
        jlb.setSize(800,500);

        int x=-jlb.getText().length()*jlb.getFont().getSize();
        int y = new Random().nextInt(500);
        jlb.setLocation(x,y);

        while (true){
            if (x++>790){
                x=-jlb.getText().length()*jlb.getFont().getSize();
            }
            jlb.setLocation(x,y);
            try {
                Thread.sleep(5);
            }catch (Exception e){
                e.printStackTrace();
            }
        }

    }
}

八、JDBC

java公司提供给开发人员的一套操作数据库的编程接口

常用api

Driver接口

driver接口是所有jdbc驱动程序必须实现的接口,该接口专门提供给数据库厂商使用。

注意:在编写jdbc程序时,必须要把所使用的数据库驱动程序或类库加载到项目的classpath中(这里指MySql驱动jar包)

DriverManager类

DriverManger类用于加载jdbc驱动并且创建与数据库的连接。

一:注册驱动
DriverManager.registerDriver(new Driver())会注册两次驱动,因为DriverManager类中的静态代码块有注册驱动的代码,通常注册驱动的方式为:**Class.forName(com.mysql.jdbc.Driver)**此语句作用为加载Driver类,从而执行其静态代码块,来注册驱动
二:获得链接
Connection getConnection(String url,String username,String password);
url写法:jdbc:mysql://localhost:3306/jdbctest
jdbc:协议
mysql:子协议
localhost:主机名
3306:端口号
jdbctest:数据库名
url简写:jdbc:mysql:///jdbctest 默认连接的数据是本机

Connection接口

Connection接口代表Java程序和数据库的连接,只要获得该连接对象后,才能访问数据库,并操作数据表。DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb", "root", "pwd");

一:创建用于执行SQL语句的对象
statement createStatement();执行SQL语句
preparedStatement prepareStatement(String sql);预编译SQL语句
CallableStatement prepareCall(String sql);执行SQL中的存储过程
二:进行事物的管理
setAutoCommit(boolean autoCommit);设置事务是否自动提交
commit();事务提交
rollback();事务回滚

Statement接口

Statement接口用于执行静态的SQL语句,并返回一个结果对象。Statement接口对象可以通过Connection实例的createStatement()方法获得,该对象会把静态的SQL语句发送到数据库中编译执行,然后返回数据库中的处理结果。它用于执行不带参数的简单SQL语句。

一:执行单条SQL语句
execute(String sql);执行SQL语句,执行select语句返回true,否则返回false
ResultSet executeQuery(String sql);执行SQL中的select语句,返回查询到的结果存入ResultSet结果集中
int executeUpdate(String sql):执行SQL中的insert/update/delete语句,返回影响的行数
二:批处理操作
addBatch(String sql):添加到批处理
executeBatch():执行批处理
clearBatch():清空批处理

PreparedStatement接口

PreparedStatement接口位于java.servlet包当中,它继承了Statement,但是PreparedStatement与Statement有这两方面的不同,第一:由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为 PreparedStatement 对象,以提高效率。作为 Statement 的子类,PreparedStatement 继承了 Statement 的所有功能。

另外它还添加了一整套方法,用于设置发送给数据库以取代 IN 参数占位符的值。

ResultSet接口

ResultSet接口用于保存JDBC执行查询时返回的结果集,该结果集封装在一个逻辑表格中。在ResultSet接口内部有一个指向表格数据行的游标(或指针)。ResultSet对象初始化时,游标在表格的第一行前,调用next()方法可将游标移动到下一行。若下一行没有数据,则返回false,在程序中经常使用next()方法作为while循环条件来迭代ResultSet结果集。

一:遍历查询的数据
next();判断是否存在下一个数据
二:获取某个特定数据
针对不同的类型的数据可以使用getXXX()来获取数据(如getInt/getLong)
getObject(String columnLabel):通过名称来获取object对象
	//1、加载数据库驱动
        Class.forName("com.mysql.jdbc.Driver");
        //2、通过DriverManager连接数据库
        Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb", "root", "pwd");
        //3、获取sql语句执行者对象
        PreparedStatement ps = connection.prepareStatement("select * from student");
        //4、运行sql语句
        ResultSet resultSet = ps.executeQuery();
        //5、处理结果集
        while (resultSet.next()){
            int studentid = resultSet.getInt("studentid");//"与数据表中的一致"
            String name=resultSet.getString("studentname");
            System.out.println(studentid+"  "+name);
        }
        //6、关闭释放资源
       connection.close();
	 //获取sql语句执行者对象
        PreparedStatement ps = connection.prepareStatement("update student set name='mary' where id=?");//占位符
        //给占位符填充数据
        ps.setObject(1,"8");
        //运行sql语句
        int i = ps.executeUpdate();
        //处理结果集
        System.out.println(i+"行受影响");

九、网络编程

网络通信协议:同一个网络中的计算机进行连接通信时必须要遵守的规则

IP地址:唯一地标识一台计算机 网络.主机

端口号:标识程序

InetAddress常用方法

//指定主机
        InetAddress byName = InetAddress.getByName("100.117.82.39");
        //获取本机主机地址
        InetAddress localHost = InetAddress.getLocalHost();
        //获取主机名
        String hostName = localHost.getHostName();
        //获取主机地址
        String hostAddress = localHost.getHostAddress();

TCP/IP

面向连接的通信协议,严格区分客户端和服务端,可以保证传输数据的安全性和完善性,常用于下载文件、重要数据的传输。

网络层次

应用层: 为互联网中的各种网络应用提供服务(http)

传输层:使网络程序进行通信(tcp、udp)

网络层:核心,将传输的数据进行分组,将分组数据发送到目标位置

链路层:物理传输通道(光纤)

 //创建服务端ServerSocket对象,指定端口号
        ServerSocket serverSocket=new ServerSocket(8888);
        //服务端响应客户端发送过来的请求
        Socket accept = serverSocket.accept();
        //获取用于传输数据的对象
        InputStream inputStream = accept.getInputStream();
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        String s = new String(bytes, 0, len);
        System.out.println("接收到数据:"+s);
        //服务端写出数据
        OutputStream outputStream = accept.getOutputStream();
        outputStream.write("收到,我很好".getBytes());
        //
        accept.close();
 //创建客户端socket对象,指定ip地址和端口号
        Socket socket=new Socket("127.0.0.1",8888);
        //获取用于数据传输的输入输出流
        OutputStream outputStream = socket.getOutputStream();
        //将数据写出
        outputStream.write("你好吗".getBytes());

        //客户端获取服务端回写的数据
        InputStream inputStream = socket.getInputStream();
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        String s = new String(bytes, 0, len);
        System.out.println("接收到数据:"+s);
        //
        socket.close();

多线程的TCP网络程序

 ServerSocket serverSocket=new ServerSocket(8888);

        while (true) {
            Socket accept = serverSocket.accept();
            new Thread() {
                @Override
                public void run() {
                    try {
                        InputStream  inputStream = accept.getInputStream();
                        OutputStream outputStream = accept.getOutputStream();
                        //使用高效流和转换流对输入流进行包装
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                         //使用打印流对输出流进行包装
                        PrintStream printStream = new PrintStream(outputStream);
                        String s = bufferedReader.readLine();
                        System.out.println("收到数据:"+s);
                        printStream.println("我很好");
                       accept.close();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
 Socket socket = new Socket("127.0.0.1", 8888);

        InputStream  inputStream = socket.getInputStream();
        OutputStream     outputStream = socket.getOutputStream();
                        //使用高效流和转换流对输入流进行包装
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                        //使用打印流对输出流进行包装
                        PrintStream printStream = new PrintStream(outputStream);
                        printStream.println("你好吗");
                        String s = bufferedReader.readLine();
                        System.out.println(s);
                        socket.close();

UDP

面向无连接,接收端和发送端不建立逻辑连接,不区分客户端和服务端,只有发送端和接收端。消耗资源小,通信效率高,延迟小。常用于音频视频和普通数据的传输

注意:要先开启接收端,否则会有数据丢失的问题,端口号要保持一致

//创建发送端的码头,随机端口号,无需指定
        DatagramSocket socket=new DatagramSocket();
        //撰写要发送的数据
        String content="你好啊";
        byte[] bytes=content.getBytes();
        //创建一个集装箱对象,用于存储数据,和数据发送
        DatagramPacket packet=new DatagramPacket(bytes,bytes.length, 						      			InetAddress.getByName("127.0.0.1 "),8888);
        //发送数据
        socket.send(packet);
		//关闭资源
        socket.close();
 //创建接收端的码头
        DatagramSocket socket=new DatagramSocket(8888);
        //创建一个集装箱对象
        DatagramPacket packet=new DatagramPacket(new byte[1024],1024);
        //将数据从对方集装箱装到自己的集装箱
        socket.receive(packet);
        //将数据从自己的集装箱中取出
        byte[] data = packet.getData();
        int len = packet.getLength();
        InetAddress ip = packet.getAddress();
        int port = packet.getPort();
        System.out.println("ip+"+ip.getHostAddress());
        System.out.println("port" + port);
        //将字节数组封装成一个字符串
        String s = new String(data, 0, len);
        System.out.println(s);
        //关闭资源
        socket.close();
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-12-15 18:08:21  更:2021-12-15 18:08:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:05:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码