有测试问题请微信联系作者,备注来意(点击此处添加)
240
一名普通的测试打工人;专注自动化测试技术研究、实践、总结、分享、交流。
用我8年+的经历,给大家带来更多实用的干货。
人若有志,就不会在半坡停止。

【JAVA基础】Java基础教程

jdk环境配置

【基础】java环境搭建及配置

基础语法


编写 Java 程序时,应注意以下几点:

  • 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。
  • 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
  • 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
  • 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为 .java。(如果文件名和类名不相同则会导致编译错误)。
  • 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。

Java 文档注释

Java 支持三种注释方式:

  • 单行注释
    //
  • 多行注释
    /*
    */
  • 文档注释
    /** 开始,以 */ 结束

Java修饰符

像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:

  • 访问控制修饰符 : default, public , protected, private
  • 非访问控制修饰符 : final, abstract, static, synchronized

访问控制修饰符

  • default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
  • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
  • public : 对所有类可见。使用对象:类、接口、变量、方法
  • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
修饰符 当前类 同一包内 子孙类(同一包) 子孙类(不同包) 其他包
public Y Y Y Y Y
protected Y Y Y Y/N(说明) N
default Y Y Y N N
private Y N N N N

非访问控制修饰符

  • static 修饰符,用来修饰类方法和类变量。
  • final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
  • abstract 修饰符,用来创建抽象类和抽象方法。
  • synchronized 和 volatile 修饰符,主要用于线程的编程。

static 修饰符

  • 静态变量:
    static 关键字用来声明独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。 静态变量也被称为类变量。局部变量不能被声明为 static 变量。
  • 静态方法:
    static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。

Java 关键字

类别 关键字 说明
访问控制 private 私有的
protected 受保护的
public 公共的
default 默认
类、方法和变量修饰符 abstract 声明抽象
class
extends 扩充、继承
final 最终值、不可改变的
implements 实现(接口)
interface 接口
native 本地、原生方法(非 Java 实现)
new 创建
static 静态
strictfp 严格浮点、精准浮点
synchronized 线程、同步
transient 短暂
volatile 易失
程序控制语句 break 跳出循环
case 定义一个值以供 switch 选择
continue 继续
do 运行
else 否则
for 循环
if 如果
instanceof 实例
return 返回
switch 根据值选择执行
while 循环
错误处理 assert 断言表达式是否为真
catch 捕捉异常
finally 有没有异常都执行
throw 抛出一个异常对象
throws 声明一个异常可能被抛出
try 捕获异常
包相关 import 引入
package
基本类型 boolean 布尔型
byte 字节型
char 字符型
double 双精度浮点
float 单精度浮点
int 整型
long 长整型
short 短整型
变量引用 super 父类、超类
this 本类
void 无返回值
保留关键字 goto 是关键字,但不能使用
const 是关键字,但不能使用

这些保留字不能用于常量、变量、和任何标识符的名称。

Java 变量类型

public class RunoobTest {
    // 成员变量
    private int instanceVar;
    // 静态变量
    private static int staticVar;
    
    public void method(int paramVar) {
        // 局部变量
        int localVar = 10;
        
        // 使用变量
        instanceVar = localVar;
        staticVar = paramVar;
        
        System.out.println("成员变量: " + instanceVar);
        System.out.println("静态变量: " + staticVar);
        System.out.println("参数变量: " + paramVar);
        System.out.println("局部变量: " + localVar);
    }
    
    public static void main(String[] args) {
        RunoobTest v = new RunoobTest();
        v.method(20);
    }
}

Java 循环结构 - for, while 及 do...while

Java中有三种主要的循环结构:

  • while 循环
  • do…while 循环
  • for 循环

while 循环

while( 布尔表达式 ) {
  //循环内容
}

do…while 循环

对于 while 语句而言,如果不满足条件,则不能进入循环。
do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次。

do {
       //代码语句
}while(布尔表达式);

for循环

for 循环,使一些循环结构变得更加简单。

for(初始化; 布尔表达式; 更新) {
    //代码语句
}

Java 增强 for 循环

主要用于数组的增强型 for 循环。

for(声明语句 : 表达式)
{
   //代码句子
}

break 关键字

break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
break 跳出最里层的循环,并且继续执行该循环下面的语句。

continue 关键字

continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
在 for 循环中,continue 语句使程序立即跳转到更新语句。
在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。

if...else语句

if 语句后面可以跟 else 语句,当 if 语句的布尔表达式值为 false 时,else 语句块会被执行。

if(布尔表达式){
   //如果布尔表达式的值为true
}else{
   //如果布尔表达式的值为false
}

Java switch case 语句

switch case 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支。

switch(expression){
    case value :
       //语句
       break; //可选
    case value :
       //语句
       break; //可选
    //你可以有任意数量的case语句
    default : //可选
       //语句
}

实例:

public class Test {
   public static void main(String args[]){
      int i = 5;
      switch(i){
         case 0:
            System.out.println("0");
         case 1:
            System.out.println("1");
         case 2:
            System.out.println("2");
         default:
            System.out.println("default");
      }
   }
}

Java 方法

  • 修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
  • 返回值类型 :方法可能会返回值。returnValueType 是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType 是关键字void。
  • 方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
    参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的参数类型、顺序和参数的个数。参数是可选的,方法可以不包含任何参数。
  • 方法体:方法体包含具体的语句,定义该方法的功能。

Java 流(Stream)、文件(File)和IO

捕获异常

使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。

try
{
   // 程序代码
}catch(ExceptionName e1)
{
   //Catch 块
}

Java继承

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

class 父类 {
}
 
class 子类 extends 父类 {
}

继承类型

Java 不支持多继承,但支持多重继承。

implements关键字

使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。

public interface A {
    public void eat();
    public void sleep();
}
 
public interface B {
    public void show();
}
 
public class C implements A,B {
}

super 与 this 关键字

  • super关键字:
    我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
  • this关键字:
    指向自己的引用。

Java 重写(Override)与重载(Overload)

Java 多态

多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作

多态的优点

  1. 消除类型之间的耦合关系
  2. 可替换性
  3. 可扩充性
  4. 接口性
  5. 灵活性
  6. 简化性

多态存在的三个必要条件

  • 继承
  • 重写
  • 父类引用指向子类对象:Parent p = new Child();

多态的实现方式

  • 方式一:重写
    这个内容已经在上一章节详细讲过,就不再阐述,详细可访问:Java 重写(Override)与重载(Overload)。

  • 方式二:接口

    1. 生活中的接口最具代表性的就是插座,例如一个三接头的插头都能接在三孔插座中,因为这个是每个国家都有各自规定的接口规则,有可能到国外就不行,那是因为国外自己定义的接口类型。
    2. java中的接口类似于生活中的接口,就是一些方法特征的集合,但没有方法的实现。具体可以看 java接口 这一章节的内容。
  • 方式三:抽象类和抽象方法

public class Test {
    public static void main(String[] args) {
      show(new Cat());  // 以 Cat 对象调用 show 方法
      show(new Dog());  // 以 Dog 对象调用 show 方法
  }  
            
    public static void show(Animal a)  {
      a.eat();  
        // 类型判断
        if (a instanceof Cat)  {  // 猫做的事情 
            Cat c = (Cat)a;  
            c.work();  
        } else if (a instanceof Dog) { // 狗做的事情 
            Dog c = (Dog)a;  
            c.work();  
        }  
    }  
}

Java 枚举(enum)

enum Color
{
    RED, GREEN, BLUE;
}
 
public class Test
{
    // 执行输出结果
    public static void main(String[] args)
    {
        Color c1 = Color.RED;
        System.out.println(c1);
    }
}

Java 数据结构

数组(Arrays)

数组(Arrays)是一种基本的数据结构,可以存储固定大小的相同类型的元素。

int[] array = new int[5];
特点: 固定大小,存储相同类型的元素。
优点: 随机访问元素效率高。
缺点: 大小固定,插入和删除元素相对较慢。

列表(Lists)

Java 提供了多种列表实现,如 ArrayList 和 LinkedList。

List<String> arrayList = new ArrayList<>();
特点: 动态数组,可变大小。
优点: 高效的随机访问和快速尾部插入。
缺点: 中间插入和删除相对较慢。
List<Integer> linkedList = new LinkedList<>();
特点: 双向链表,元素之间通过指针连接。
优点: 插入和删除元素高效,迭代器性能好。
缺点: 随机访问相对较慢。

集合(Sets)

集合(Sets)用于存储不重复的元素,常见的实现有 HashSet 和 TreeSet。

Set<String> hashSet = new HashSet<>();
Set<Integer> treeSet = new TreeSet<>();
特点: 无序集合,基于HashMap实现。
优点: 高效的查找和插入操作。
缺点: 不保证顺序。

映射(Maps)

映射(Maps)用于存储键值对,常见的实现有 HashMap 和 TreeMap。

Map<String, Integer> hashMap = new HashMap<>();

特点: 基于哈希表实现的键值对存储结构。
优点: 高效的查找、插入和删除操作。
缺点: 无序,不保证顺序。

HashMap对应的Python中的字典功能

Map<String, Integer> treeMap = new TreeMap<>();
特点: 基于红黑树实现的有序键值对存储结构。
优点: 有序,支持按照键的顺序遍历。
缺点: 插入和删除相对较慢。

栈(Stack)

栈(Stack)遵循先进后出(FILO)原则。

Stack<Integer> stack = new Stack<>();
特点: 代表一个栈,通常按照后进先出(LIFO)的顺序操作元素。

队列(Queue)

队列(Queue)遵循先进先出(FIFO)原则,常见的实现有 LinkedList 和 PriorityQueue。

Queue<String> queue = new LinkedList<>();
特点: 代表一个队列,通常按照先进先出(FIFO)的顺序操作元素。
实现类: LinkedList, PriorityQueue, ArrayDeque。

堆(Heap)

堆(Heap)优先队列的基础,可以实现最大堆和最小堆。

PriorityQueue<Integer> minHeap = new PriorityQueue<>();
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());

树(Trees)

Java 提供了 TreeNode 类型,可以用于构建二叉树等数据结构。

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

其他

枚举(Enumeration)

枚举(Enumeration)接口虽然它本身不属于数据结构,但它在其他数据结构的范畴里应用很广。 枚举(The Enumeration)接口定义了一种从数据结构中取回连续元素的方式。

位集合(BitSet)

位集合(BitSet)
位集合类实现了一组可以单独设置和清除的位或标志。
该类在处理一组布尔值的时候非常有用,你只需要给每个值赋值一"位",然后对位进行适当的设置或清除,就可以对布尔值进行操作了。

向量(Vector)

向量(Vector)类和传统数组非常相似,但是Vector的大小能根据需要动态的变化。
和数组一样,Vector对象的元素也能通过索引访问。
使用Vector类最主要的好处就是在创建对象的时候不必给对象指定大小,它的大小会根据需要动态的变化。

栈(Stack)

栈(Stack)实现了一个后进先出(LIFO)的数据结构。
你可以把栈理解为对象的垂直分布的栈,当你添加一个新元素时,就将新元素放在其他元素的顶部。
当你从栈中取元素的时候,就从栈顶取一个元素。换句话说,最后进栈的元素最先被取出。

字典(Dictionary)

字典(Dictionary) 类是一个抽象类,它定义了键映射到值的数据结构。
当你想要通过特定的键而不是整数索引来访问数据的时候,这时候应该使用 Dictionary。
由于 Dictionary 类是抽象类,所以它只提供了键映射到值的数据结构,而没有提供特定的实现。

Dictionary 类在较新的 Java 版本中已经被弃用(deprecated),推荐使用 Map 接口及其实现类,如 HashMap、TreeMap 等,来代替 Dictionary。

哈希表(Hashtable)

Hashtable类提供了一种在用户定义键结构的基础上来组织数据的手段。
例如,在地址列表的哈希表中,你可以根据邮政编码作为键来存储和排序数据,而不是通过人名。
哈希表键的具体含义完全取决于哈希表的使用情景和它包含的数据。

属性(Properties)

Properties 继承于 Hashtable.Properties 类表示了一个持久的属性集.属性列表中每个键及其对应值都是一个字符串。
Properties 类被许多Java类使用。例如,在获取环境变量时它就作为System.getProperties()方法的返回值。

Java 泛型

泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

java 中泛型标记符:

  • E - Element (在集合中使用,因为集合中存放的是元素)
  • T - Type(Java 类)
  • K - Key(键)
  • V - Value(值)
  • N - Number(数值类型)
  • ? - 表示不确定的 java 类型
import java.util.*;

class GenericTest {

    public static void main(String[] args) {
        List<String> name = new ArrayList<String>();                    //<xxx> 声明参数类型
        List<Integer> age = new ArrayList<Integer>();
        List<Number> number = new ArrayList<Number>();

        name.add("icon");
        age.add(18);
        number.add(314);

        getData(name);
        //getUperNumber(name);    // 泛方法中未指定String,所以会报错
        getUperNumber(age);    // 调用泛方法
        getUperNumber(number);

    }

    public static void getData(List<?> data) {                          //? 通配符,可以传任意参数类型
        System.out.println("data :" + data.get(0));
    }

    public static void getUperNumber(List<? extends Number> data) {     //extend 指定参数类型
        System.out.println("data :" + data.get(0));
    }
}

Java序列化

  • 序列化(Serialization):
    将java对象以一连串的字节保存在磁盘文件中的过程,也可以说是保存java对象状态的过程。序列化可以将数据永久保存在磁盘上(通常保存在文件中)。
  • 反序列化(deserialization):
    将保存在磁盘文件中的java字节码重新转换成java对象称为反序列化。

序列化对象

ObjectOutputStream 类用来序列化一个对象,如下的 SerializeDemo 例子实例化了一个 Employee 对象,并将该对象序列化到一个文件中。
该程序执行后,就创建了一个名为 employee.ser 文件。该程序没有任何输出,但是你可以通过代码研读来理解程序的作用。

import java.io.*;
 
public class SerializeDemo
{
   public static void main(String [] args)
   {
      Employee e = new Employee();
      e.name = "Reyan Ali";
      e.address = "Phokka Kuan, Ambehta Peer";
      e.SSN = 11122333;
      e.number = 101;
      try
      {
         FileOutputStream fileOut =
         new FileOutputStream("/tmp/employee.ser");
         ObjectOutputStream out = new ObjectOutputStream(fileOut);
         out.writeObject(e);
         out.close();
         fileOut.close();
         System.out.printf("Serialized data is saved in /tmp/employee.ser");
      }catch(IOException i)
      {
          i.printStackTrace();
      }
   }
}

反序列化对象

下面的 DeserializeDemo 程序实例了反序列化,/tmp/employee.ser 存储了 Employee 对象。

import java.io.*;
 
public class DeserializeDemo
{
   public static void main(String [] args)
   {
      Employee e = null;
      try
      {
         FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
         ObjectInputStream in = new ObjectInputStream(fileIn);
         e = (Employee) in.readObject();
         in.close();
         fileIn.close();
      }catch(IOException i)
      {
         i.printStackTrace();
         return;
      }catch(ClassNotFoundException c)
      {
         System.out.println("Employee class not found");
         c.printStackTrace();
         return;
      }
      System.out.println("Deserialized Employee...");
      System.out.println("Name: " + e.name);
      System.out.println("Address: " + e.address);
      System.out.println("SSN: " + e.SSN);
      System.out.println("Number: " + e.number);
    }
}

Java中API请求

Java内置的URLConnection类

URLConnection类,是一个用于创建和管理与URL之间的连接的类。我们可以使用它来发送HTTP请求并获取响应。

import java.net.*;
import java.io.*;
class URLConnDemo
{
    public static void main(String [] args)
    {
        try
        {
            URL url = new URL("http://www.baidu.com");
            URLConnection urlConnection = url.openConnection();     // 创建URLConnection对象

            HttpURLConnection connection = (HttpURLConnection) urlConnection;     // 将urlConnection对象转换为HttpURLConnection对象
            connection.setRequestMethod("GET");     // 设置请求方法(GET、POST等)
            connection.setRequestProperty("User-Agent", "Mozilla/5.0");     // 设置请求头

            BufferedReader reader = new BufferedReader(
                    new InputStreamReader(connection.getInputStream()));    // 发起请求
            String line;
            StringBuilder response = new StringBuilder();       // 创建response对象

            while ((line = reader.readLine()) != null) {        // 读取并写入response
                response.append(line);                          
            }
            reader.close();
            System.out.println(response.toString());         // 打印响应数据
        }catch(IOException e)
        {
            e.printStackTrace();
        }
    }
}

使用第三方库

常用的Java HTTP客户端库:

  • Apache HttpClient
  • OkHttp
  • Retrofit

HttpClient进行API请求

import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

public class HelloWord {
    public static void main(String[] args) throws Exception {
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpGet httpGet = new HttpGet("http://www.baidu.com");              // 定义请求方法(GET、POST)
        CloseableHttpResponse response = httpClient.execute(httpGet);           // 发送请求
        if (response.getStatusLine().getStatusCode() == 200) {
            String responseBody = EntityUtils.toString(response.getEntity());   //  获取响应内容
            System.out.println(responseBody);
        }
        response.close();
        httpClient.close();
    }
}

Java 网络编程

java.net 包中提供了两种常见的网络协议的支持:

  • TCP:
    TCP(英语:Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。

  • UDP:
    UDP (英语:User Datagram Protocol,用户数据报协议),位于 OSI 模型的传输层。一个无连接的协议。提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。

Socket 编程

套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。

以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:

  1. 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。
  2. 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。
  3. 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。
  4. Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。
  5. 在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。
  6. 连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流。

TCP 是一个双向的通信协议,因此数据可以通过两个数据流在同一时间发送。以下是一些类提供的一套完整的有用的方法来实现 socket。

Socket 客户端实例

如GreetingClient是一个客户端程序,该程序通过 socket 连接到服务器并发送一个请求,然后等待一个响应。

// 文件名 GreetingClient.java
package com;

import java.net.*;
import java.io.*;

public class GreetingClient {
    public static void main(String [] args)
    {
        String serverName = "localhost";
        int port = 8082;
        try
        {
            System.out.println("连接到主机:" + serverName + " ,端口号:" + port);
            Socket client = new Socket(serverName, port);   // 创建Socket对象,参数为:地址和端口号
            System.out.println("远程主机地址:" + client.getRemoteSocketAddress());    // 获取此套接字连接的端点的地址,如果未连接则返回 null
            OutputStream outToServer = client.getOutputStream();    // 创建此套接字的输出流
            DataOutputStream out = new DataOutputStream(outToServer);

            out.writeUTF("Hello 你好啊 " + client.getLocalSocketAddress());    // 发送输出流给连接端
            DataInputStream in = new DataInputStream(client.getInputStream());      // 获取此套接字的输入流并创建此对象
            System.out.println("服务器响应: " + in.readUTF());       // 读取输入流并打印
            client.close();
        }catch(IOException e)
        {
            e.printStackTrace();
        }
    }
}

Socket 服务端实例

如GreetingServer程序是一个服务器端应用程序,使用 Socket 来监听一个指定的端口。

// 文件名 GreetingServer.java
package com;

import java.net.*;
import java.io.*;

public class GreetingServer extends Thread {
    private ServerSocket serverSocket;

    public GreetingServer(int port) throws IOException
    {
        serverSocket = new ServerSocket(port);  // 创建绑定到特定端口的服务器套接字
        serverSocket.setSoTimeout(60000);      // 通过指定超时值(服务等待时间),以毫秒为单位。
    }

    public void run()
    {
        while(true)
        {
            try
            {
                System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");   // 获取此套接字绑定到的本地端口
                Socket server = serverSocket.accept();      // 该方法将一直等待,直到客户端连接到服务器上给定的端口
                System.out.println("远程主机地址:" + server.getRemoteSocketAddress());    // 获取此套接字连接的端点的地址,如果未连接则返回 null
                DataInputStream in = new DataInputStream(server.getInputStream());  // 获取此套接字的输入流并创建此对象
                System.out.println(in.readUTF());   // 读取输入流并打印
                DataOutputStream out = new DataOutputStream(server.getOutputStream());  // 获取此套接字的输出流
                out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "\nGoodbye!"); // 发送输出流给连接端
                server.close();
            }catch(SocketTimeoutException s)        // Socket超时异常处理
            {
                System.out.println("Socket timed out!");
                break;
            }catch(IOException e)
            {
                e.printStackTrace();
                break;
            }
        }
    }
    public static void main(String [] args)
    {
        int port = 8082;
        try
        {
            Thread t = new GreetingServer(port);    // 创建GreetingServer的线程对象
            t.start();          // 运行线程
        }catch(IOException e)
        {
            e.printStackTrace();
        }
    }
}

先运行服务端,客户端再进行连接,执行结果如下:


Java 多线程编程

  • 进程:
    一个进程包括由操作系统分配的内存空间,包含一个或多个线程。
  • 多线程
    多任务的一种特别的形式,但多线程使用了更小的资源开销。

Java 提供了三种创建线程的方法:

  • 通过实现 Runnable 接口
  • 通过继承 Thread 类本身
  • 通过 Callable 和 Future 创建线程

创建线程的三种方式的对比

  1. 采用实现 Runnable、Callable 接口的方式创建多线程时,线程类只是实现了 Runnable 接口或 Callable 接口,还可以继承其他类。
  2. 使用继承 Thread 类的方式创建多线程时,编写简单,如果需要访问当前线程,则无需使用 Thread.currentThread() 方法,直接使用 this 即可获得当前线程。

线程的几个主要概念

  • 线程同步
  • 线程间通信
  • 线程死锁
  • 线程控制:挂起、停止和恢复

使用Thread创建线程Demo

package com;

public class ThreadDemo extends Thread {
    private int number;
    public ThreadDemo(int number) {
        this.number = number;
    }

    public void run() {
        int counter = 0;
        int rd = 0;
        do {
            rd = (int) (Math.random() * 100 + 1);
            System.out.println("当前进程 " +this.getName() + "生成随机数:" + rd);
            counter++;
        } while(rd != number);
        System.out.println("当前进程 " + this.getName() + " 猜了" + counter + "次找到了");
    }
    public static void main(String [] args){
        Thread t1 = new ThreadDemo(2);
        Thread t2 = new ThreadDemo(2);
        Thread t3 = new ThreadDemo(2);
        t1.start();
        t2.start();
        t3.start();
    }
}

Java基础学习教程

java菜鸟教程
java菜鸟教程

Java实例

菜鸟Java实例
菜鸟Java实例

Java测验

菜鸟Java测验

posted @ 2024-01-15 18:07  三叔测试笔记  阅读(20)  评论(0编辑  收藏  举报
返回顶部 跳转底部