JAVA_基础知识

1、JAVA体系基础

1.1、JAVA 体系


  • 标准版 :Java SE (Java Standard Edition)
  • 企业版 :Java EE (Java Enterprise Edition)
  • 小型版 :Java ME (Java Micro Edition)
  • 小程序 :Java Card (运行在小内存设备上的平台)

1.2、JDK下载地址


  • JDK 下载地址 :https://www.oracle.com/cn/java/
  • JDK 关系 :JDK > JRE > JVM
    • JDK (软件开发工具包)— 编写程序
    • JRE (软件运行环境) — 运行软件运行程序
    • JVM (Java虚拟机) — 计算设备规范,通过实际计算机上仿真模拟各种计算机功能实现
  • 常用编译工具 :Notepad++ 、Sublime

1.3、注释说明


  • 注释分类 :单行注释、多行注释、多行(文档注释)
  • 单行注释 :从 // 开始,到本行结束,都是注释
  • 多行注释 :从/* 开始,到*/结束,中间所有都是注释
  • 多行注释 :从/*开始,到/结束,是一种支持提取的注释

1.4、变量、常量


  • 常量: 程序在运行期间不发生变化的量
  • 变量: 程序在运行期间发生变化的量 ( 声明方式 : 数据类型 变量名 = 初始值)
class HelloWorld{
	public static void main(String[] args){
		// 定义一个变量,定义一个整数类型的变量,名字为age,它的值为10
		int age = 10;
		System.out.printIn(age);
		// 修改age变量的值
		age = 20;
		System.out.println("age变化后的值是:" + age);
	}
}
1.4.1、局部变量的使用

  • 定义位置 :在方法的内部或语句块内
  • 变量一定要赋初始值,否则在使用是会报错
  • 变量名不能重复(在同一个作用域内)
  • 栈区存放程序当中所有的局部变量
class Demo{
	public static void main(String[] args){
	
		// 定义byte类型
		byte age = 127;
		System.out.println(age);		
	}
	public void method(){
		int age = 18;
	}
}
1.4.2、成员变量

  • 数值类型 :默认值为 0
  • boolean型 :false
  • 引用类型 :null
public class Person{
	String name;
	int age;

	// 成员方法 : 成员变量和成员方法属于类内部成员,可直接访问
	void show(){
		System.out.println("年龄"+ age )
	}

	void setName(String s){
		name = s;
	}

	void setAge(int i){
		age = i;
	}

	// 有返回值的函数
	String getName(){
		return name;
	}

	// 修改传递多参数
	void setNameAge(String s,int i){
		name = s;
		age = i;
	}

	// 可变长参数(可看作一维数组)
	void showArgument(String... args){
		for(int i=0;i<args.length;i++){
			System.out.println("第" + i + "个参数是" + args[i])
		}
	}
	
	
	public static void main(String[] args){
		// 类的实例化, 数据类型(类名) 引用变量名 = new 类名();
		Person p = new Person();
		p.name = "lcl";
		p.age = 18;
		
		// 方法的调用
		p.show();
		p.setName("lcl")
		p.setAge(18)
		p.setNameAge("lcl",18)
		p.showArguement("参数1","参数2","参数3")
		String myName = p.getName()
		System.out.println("名字"+ name )
		
	}
}

2、数据类型

2.1、基本数据类型


  • 基本数据类型
    • byte、shot、int、long、float、double、boolean、char
  • 引用数据类型
    • 数组、类、接口、枚举、标注
类型占用存储空间表示范围
byte1字节=8bit-128~127
short2字节-2(15次方)~2(15次方-1)
int4字节-2(31次方)~ 2 (31次方-1)
long8字节-2(63次方)~ 2(63次方-1)
class Demo{
	public static void main(String[] args){
	
		// 定义byte类型
		byte age = 127;
		System.out.println(age);
		
		// 定义short类型
		short persnonCount = 1000;
		System.out.println(persnonCount);

		// 定义longth类型,定义的时候数值后面可以加1
		long starCount = 100000001;
		System.out.println(starCount);
	}
}

2.2、数据类型转化


  • 自动类型转换 : 自动类型转换主要指从小类型到大类型之间的转换
    • byte —>short (char) —>int —>long —>float —>double
  • 强制类型转化 : 强制类型转换主要指从大类型到小类型之间的转换
    • 目标类型 变量名 = (目标类型)源类型变量名;
    • double —>float —>long —>int —>short (char) —>byte
class Demo{
	public static void main(String[] args){
		int i = 10
		// 数据类型强制转化,前提精度不会损失
		byte age = (byte)i;
		System.out.println(age);	
		}	
	}

3、运算符


  • 算数运算符
  • 赋值运算符
  • 关系运算符
  • 逻辑运算符
  • 位运算符
  • 三元运算符

3.1、算数运算符


class Demo{
	public static void main(String[] args){
		int a = 10
		int b = 15
		//  + - * /    加减乘除运算符   % 取余数
		int c = a + b;
		int d = a - b;
		int e = a * b;
		// int 间 做除法是整数
		int f = a / b;
		
		System.out.println(c)
		}	
	}
``


**变量叠加**

 - ++  --  给数值变量自身加 1 或 减1
```java
class Demo{
	public static void main(String[] args){
		// 后 ++ ( a = a + 1)
		int a = 1;
		a++ ; 
		System.out.println(a)   //2

		int b = 1
		// 如果后 ++ 和使用这个后加加一起运算使用的时候,使用的是  +1 之前的值
		System.out.println(b++) ;  // 1
		System.out.println(b);   // 2
		
		// 前 ++
		int a = 1;
		++a;
		System.out.println(b);   // 2
		// 如果前 ++ 和使用这个后加加一起运算使用的时候,使用的是  +1 之后的值
		System.out.println(++b) ;  // 2
		}	
	}

3.2、赋值运算符


class Demo1{
	// =,+=,-=,*=,/=,%=
	public static void main(String[] args){
		int a = 10;
		a += 10;
		System.out.println(a);
		short.out.println(a);
		 }
		}

3.3、逻辑运算符


运算符含义
&与/and
&&与/and
竖竖或/or
竖竖双或/or

3.4、判断运算符


3.4.1、IF 分枝判断

class Demo1{
	public static void main(String[] args){
		int score = 90;
		if (score >= 60){
		System.out.println("恭喜你及格了");
		}else if(score >= 80){
		System.out.println("你打了个优秀");
		}else if(score>=90){
		System.out.println("你打了90多分");
		}else{
		System.out.println("你没及格");}
		
		}
	}
3.4.2、Switch 分枝判断

// 不要漏掉 break

public class demo02 {

    public static void main(String[] args){
        String grade = "F";

        switch (grade){
            case "A":
                System.out.println("优秀");
                break;
            case "B":
                System.out.println("良好");
                break;
            case "C":
                System.out.println("及格");
                break;
            case "D":
                System.out.println("不及格");
                break;
            default:
                System.out.println("未匹配");
        }
    }
}
3.4.3、三元运算符

  • 语法 :逻辑表达式2 ? 表达式3: 表达式4
class Demo1{
	public static main(String[] args){
		int gender = 2;
		// 三元运算符、可以是常量、变量、表达式
		char c = gender ==1?'男':'女'System.out.pringln(c);
		}
	}
3.4.4、循环结构(while)

class Demo11{
	public static void main(String[] args){
		int i = 1
		while(i<= 100){
			System.out.println(i);
			i ++;
			}
			System.out.println("结束")
		}
	}
3.4.5、do…while循环

  • 语法:do { 循环体 } while(表达式)
class Demo12{
	public static void main(String[] args){
		int i = 1
		do {
			if (i % 2 == 0){
				total += i;
				}
				i ++;
			}while(i<= 100);
			System.out.println("结束")
		}
	}
3.4.6、for 循环

  • 语法 : for (表达式1;表达式2;表达式3) { 循环体}
  • 表达式1 :计数器的初始化,它只初始化一次
  • 表达式2 :循环条件的判断,多次执行
  • 表达式3 :修改计数器,多次执行
class Demo12{
	public static void main(String[] args){
		int i = 1
		for (int i = 1;i<= 1000;i++){
			if( i == 5){
				continue;
				}	
			System.out.println(i);
			}
		}
	}
3.4.7、案例代码

import java.util.Scanner;

public class demo05 {
    public static void main(String[] args) {
        // 从键盘输入不确定的整数,并判断正数和复数的个数
        // 创建接收控制台输入的对象
        Scanner scanner =  new Scanner(System.in);
        int i = 0,a = 0,b = 0;
        do {
            System.out.println("请输入一个整数");
            i = scanner.nextInt();
            if(i>0){a++;};
            if(i<0){b++;};

        }while (i!=0);
        System.out.println("结束循环");
        System.out.println("输入正数个数" + a);
        System.out.println("输入负数个数" + b);

    }
}

4、数 组

  • 一维数组 :记录多个类型相同的数据内容,内存中申请一段连续的存储单元,元素按照线性排列
    • 声明方式 1 ( 数组类型【】 数组名称 = new 数据类型【数组长度】)
    • 声明方式2 (数据类型【】 数组名称 = {初始值1,初始值2,初始值3,…})
    • length属性可以获取数组长度、下标从 0 开始
  • 二维数组 :多个一维数组组成
    • 声明方式 1 ( 数组类型【】【】 数组名称 = new 数据类型【行数】【列数】)
    • 声明方式2 (数据类型【】 数组名称 = {{初始值1,初始值2,初始值3},…})

4.1、数组工具类


  • java.util.Arrays类
    • static String toString(int[] a) 输出数组内容
    • static void fill(int[] a,int val) 将参数指定元素赋值给数组中的元素
    • static bookean equals(boolean[] a,boolean[] a2) 判断两个数组元素内容和次序是否相同
    • staic void sort(int[] a) 对数组中的元素进行从小到大的排序
    • staic int binarySearch(int[] a,int key) 从数组中查找参数指定元素所在位置

5、面向对象编程

  • 面向对象的特性 : 封装、继承、多态
  • 类与对象 :类(class)、对象(object)
    • 类是 对 一类事物描述,是抽象的 (属性 + 行为)
    • 对象 是 实际存在的该类 事务的每个个体,因而称之为实例
    • 堆区用于存放所有 new 产生的对象 和数组

5.1、类的基本语法


修饰符 class 类名{
	属性声明;  // 修饰符 类型 属性名=初值;
	方法声明;
}

// 修饰符 public :类可以被任意访问
// 类的正文要用 {} 括起来


// 方法
修饰符 返回值类型 方法名(参数列表){
	方法体语句;
}
// 修饰符 : public , private , protected
// 返回值类型 : return 语句传递返回值。没有返回值 :void
修饰符类内部同一个包子类任何地方
privateyes
空白yesyes
protectedyesyesyes
publicyesyesyesyes

5.2、函数的调用


class Demo1{
	public static void main(String[] args){
		int a = 10;
		int b = 19;
		// 调用写好的方法,使用返回值来接收方法的返回结果
		int result = compareNum(a,b);
		System.out.println(result+"大")}
		
	// 如果一个方法是 void 那么我们不需要返回值,所以不需要写 return 变量值
	public static int compareNum(int a,int b){
		int c = 0;
		if (a > b){
		c =  a;
		}else{
			c = b ;
			}
			return c;
		}
	}
// public 公开类
public class Person{
	// 成员变量   姓名-属性 - 公开属性
	public String name;
	// 成员变量    年龄 - 属性 - 私有属性
	private int age;
	// 工作 - 行为
	public void work(){
		System.out.println("正在工作...")}
	// 唱歌 - 行为
	// 方法规则 :修饰符 + 返回值类型 + 方法名(参数类型,参数名称)
	public void sing(){
		System.out.println("正在唱歌...")}
	private int sum(int a,int b){
		int c = a+b;
		return c;
		}
	// 自己的类中访问私有属性
	public void showInfo(){
		float height = 1.8f;  // 局部变量 -必须赋值 - 外部无法访问
		System.out.println("姓名:" +name+"年龄:" +age)}
}


//类的实例化
public class App{
	// 类中方法的语法格式:
	// 修饰符  + 返回值类型 + 方法名(参数类型 参数名称){方法体语句:}
	// 修饰符 : (public - 公开方法) (protected-类内+同包+子类) (缺省-类内部+同包) (private-内部调用)    
	// 返回值类型 : return 语句传递返回值,没有返回值用:void
	// static 修饰称为静态方法,被调用时 ,不需要进行实例化类,直接通过类名调用方法即可
	// 在静态方法中不能使用非静态变量
	public static void main(String[] args){
		// 再调用类中方法前,需要创建方法的类,创建一个Person类型对象,名为person1
		Person person1 = new Person();
		// 调用person 实例化后person1中的sum方法,传入a,b两个参数,用 int 类型的 result进行接收返回值
		int result = person1.sum(a,b)
		// 创建一个Person类型对象,名为person2
		Person person2 = new Person();
		System.out.println(person1.name)System.out.println(person1.age)// 无法访问,私有属性
		}}

5.3、不定参数的使用

public class App{
	public static void main(String[] args){
		// 定义一个方法用于计算多个整数的和
		App.sum(1,2,3)
		}
	
	public static int sum(int ... a){
		//采用循环遍历参数
		int result = 0
		for(int i = 0;i<a.length;i++){
			System.out.println(a[i])
			result = a[i]+result;  // result += a[i]
			}
			return result;
		}
	}

5.4、构造方法


// 构造方法与类名完全相同,并且没有返回类型,连void都不允许有

class Person{
	// 构造方法
	Person(){
		"构造方法体"
	}
}
5.4.1、this 基本概念

  • 再构造方法中 ,代表当前正在构造的对象
  • 成员方法中,代表当前调用的对象
public class ThisTest{
	ThisTest(){
		// 当前正在构造的对象
		System.out.println("构造方法: this" + this )
	}
	
	void show(){
		//  自定义成员方法(谁调用show 就是谁)
		System.out.println("成员方法")
	}
}
5.4.2、this懒人原则

public class Person{
	String name;
	int age;
	
	// 成员变量与方法参数名称一致时
	Person(String name,int age){
		this.name = name;
		this.age = age;
	}
	
	
	Person getPerson(){
		// 返回当前调用对象
		return this;
	}

}
public class Boy{
	String name;
	
	Boy(){
		System.out.pringln("无参数")
	}
	
	Boy(String name){
		// 调用无参方法
		this();  
		System.out.pringln("有参数"+ name)
	}
}

5.5、方法的重载


public class App{
	public static void main(String[] args){
		// 定义一个方法用于计算多个整数的和
		// 根据传参的数据类型不同,自动识别调用哪一个函数,参数个数也可以识别
		App.sum(1,2,3)
		}
	
	
	public static int sum(int a,int b){
			return a+b;
		}
	public static double sum(double a,double b){
			return a+b;
		}
	}

5.6、JAVA 继承


// 通过extends关键字可以声明一个类是从另外一个类继承而来
// 格式如下:
class "父类名"{
	// 体函数
}
class "子类名" extends "父类名"{
	// 子类继承父类内容 + 新写入的内容
}

//定义动物类
public class Animal{
	public String name;
	public int id;

	public void eat(){
		System.out.println(name+"正在吃饭");
	}
	public void sleep(){
		System.out.println(name+"正在睡觉");
	}
	public void showInfo(){
		System.out.println("我叫"+name+"我的编号是"+id);
	}
}

// 定义老鼠类,继承Animal - 不支持 同时继承两个父类
// 私有的部分 private 不能被继承
public class Mouse extends Animal{}
// 定义企鹅类,继承Animal
public class Penguin extends Animal{}

// 类的继承后调用其方法依然有效
public class App{
	public static void main(String[] args){
	Penguin penguin = new Penguin();
	penguin.id =1
	penguin.name = "小企鹅";
	
	penguin.eat();
	penguin.sleep();
	penguin.showInfo();
	}
}

5.7、定义抽象类


  • 当一个类继承抽象类后,必须重写抽象方法,否则该类也将变成抽象类
  • 抽象类具有强制性和规范性,因此叫做模板设计模式
  • 抽象类 : 不能具体实例化的类,并且使用abstract关键字修饰,不能创建对象
  • 抽象类可以有成员变量,可以有构造方法,成员方法
  • 抽象方法:不能具体实现的方法,并且使用abstract关键字修饰,没有方法体
// 定义抽象类 - 可定义抽象方法
public abstract class Animal{
	public String name;
	public int id;
	
	// 定义抽象方法 - 用于强制子类重写,子类继承时必须重写
	public abstract void test();

	// 子类中对test方法进行了重写 、但是想调用父类中的test方法 - 通过 super 完成
	super.test();
	// 调用当前类的test() 方法
	this.test()
}


// final 修饰的类不能被继承
public final class "类名"{
	//类体
}

5.8、final 类


  • final关键字修饰 类 ,该类不能被继承
  • final关键字修饰 成员方法, 不能被重写,但可以被继承
  • final关键字修饰 成员变量,该变量必须初始化,且不能改变
// final 类不能被任何子类所继承
public final class Animal{}

5.9、常见异常


  • 算数异常
  • 数组下标越界异常
  • 空指针异常 - NullPointertion

5.10、封装的概念


  • 为了避免一些错误的发生,需要对成员变量进行一些密封包装处理,来隐藏成员变量的细节及保证变量值得合理性,该机制 被叫做封装
/*
1、私有化成员变量 - private(私有化) - 只能在类的内部使用
2、提供公有的(public) get、set 方法,并在方法体中进行合理值的判断
3、在构造方法中也需要调用set方法 进行合理判断 
*/

public class Student{
	private int id;
	private String name;

	// 构造方法
	public Student(){}
	public Student(int id,String name){
		setId(id);
		setName(name);
	}

	public int getId(){
		return id;
	}

	public int setId(int id){
		if(id > 0){
			this.id = id;
		}else{
			System.out.println("学号不合理")
		}
	}

	public String getName(){
		return name;
	}
	
	public void setName(String name){
		this.name = name;
	}

	void show(){
		System.out.println("我是" + name + ",我的学号是" + id);
		System.out.println("我是" + getName() + ",我的学号是" + getId());
	}
}


public class StudentTest{
	public static void main(String[] args){
		Student s1 = new Student();
		s1.setId(1001);
		s.setName("张飞");
		s1.show();

		Student s2 = new Student(-1001,"张飞");
		s2.show;
	}
}
public class StudentTest2{
	public static void main(String[] args){
		System.out.println("请输入学生人数");
		Scanner sc = new Scanner(System.in);
		int num = sc.nextInt();

		// 声明长度为 num,类型为 Student类型的一维数组,其中每个元素都看作是 Student类型的变量
		Student[] arr = new Student[num];
		
		// 提示用户输入每个学生的信息(学号 姓名)并记录到一维数组中
		for(int i =1;i<num;i++){
			System.out.println("请输入第" + (i+1) + "个学生的信息(学号、姓名):");
			arr[i] = new Student(sc.nextInt(),sc.next());
		}

		// 打印所有学生的类
		System.out.println("该班级的所有学生信息有"):
		for (int i =0;i<num;i++){
			System.out.println(arr[i]);   // 此处打印出来的是地址
			arr[i].show()
		}
	}
}

5.11、static 关键字


  • static 修饰成员变量,将变量由对象层级提升为类层级,被整个类共享,该成员随着加载准备就绪,与是否创建对象无关( 类名.变量名 )
  • 对象中只要有一个对象改变了它的值,那么全员在使用时都使用改变后的值。一共只有一个对象
  • 非静态成员方法中,既能访问非静态成员又能访问静态成员(成员 : 成员变量+成员方法,静态成员被所有对象共享)
  • 在静态方法中,只能访问静态成员,不能访问非静态成员(成员 : 成员变量+成员方法,因为此时可能还没有创建对象)
public class people{
	private String name;
	private int age;
	private static String country;  // 静态变量,全员共享
	public People(){}
	public People(String name,int agey){
		setName(name);
		setAge(age);
		setCountry(country);
	}

	public String getName(){
		return name;
	}

	public void setName(String name){
		this.name = name;
	}

	public void setAge(){
		return age;
	}

	public void setAge(int age){
		if(age>0 && age <15){
			this.age = age;
		}else{
			System.out.println("年龄不合理")
		}
	}
}


public class StaticTest{
	private int cnt = 1;  // 隶属于对象层级,每个对象都有独立的一份
	private static int snt = 2; // 隶属类层级,所有的对象共享一个

	// 定义非静态成员方法
	public void show(){
		System.out.println("cnt=" + cnt); //  1
		System.out.println("cnt=" + snt); //  2
	}	
	
	//自定义静态成员方法,推荐使用 类名.的方式 访问 
	public static void test(){
		System.out.println("cnt=" + cnt); // 静态成员方法只能调用静态成员变量
		System.out.println("cnt=" + snt); //  静态成员方法没有this 关键字,因为是通过类名.的方式调用的
	}
}


public static void main(String[] args){
	staticTest st = new StaticTest();
	st.show();
	StaticTest.test();	
}

5.12、构造块和静态代码块


  • 构造块 : 在类体中直接使用{}括起来的代码块
  • 每创建一个对象 都会执行一次构造块
  • 静态代码块 : 用static 修饰的 代码块称为静态代码块
  • 静态代码块只执行一次就完毕了,先于构造块执行
/*
执行顺序 - 静态代码块 - 构造块(对成员变量统一的初始化) - 构造方法体 -  构造块 - 构造方法体
*/
public class BlockTest{
	// 构造块 - 随着对象创建而每次都会执行
	{ System.out.println("构造块- 准备工作写于此处");}     // 构造块

	// 静态代码块 - 用 static 修饰的代构造块
	static {System.out.println("静态代码块");}

	// 构造方法
	public BlockTest(){
		System.out.println("构造方法体")
	}

	// 静态代码块 - 用 static 修饰的代构造块
	public static void main(String[] args){
		BlockTest bt = new BlockTest();
	}
}
5.12.1、static 案例

/*
编程实现Singleton类的封装
实现SingletonTest类对Singleton 类进行测试,要求 main 方法中能得到且只能得到该类的一个对象
在Singleton 中封装new   方法
*/
public class Singleton{
	// 2.声明本类类型的引用指向本类类型对象 - 对象层级提升类层级
	private static Singleton s1 = new Singleton();
	// 1.私有化构造方法-不能再类外不能 new 
	private Singleton(){};
	// 3.提供公有的get方法将对象返回出去
	public static Singleton getInstance(){
        return s1;
    }
}


public class SingletonTest{
	public static void main(String[] args)
		//Singleton s1 = new Singleton();
		//Singleton s2 = new Singleton();
		Singleton s1 = Singleton.getInstance();
		Singleton s2 = Singleton.getInstance();
		System.out.println(s1==s2)  // true		
}
5.12.2、单例类

  • 对外提供且只提供一个对象,这样的类叫做单例类
  • 而设计单例的流程和思想叫做单例设计模式
  • 任务管理器,操作多次都提供一个类
public class Singleton{
	// 声明本类类型的引用指向本类类型的对象,使用private static 关键字共同修饰
	private static Singleton sin = new Singleton();
	// 私有化构造方法,使用private 关键字修饰
	private Singleton(){}
	// 提供共有的 get 方法负责将对象返回出去,使用public关键字共同修饰
	public static Singleton getInstance(){
		return sin;
	}
}

继承特点

  • 子类不能继承父类的构造方法和私有方法,但私有成员变量可以继承只是不能直接访问
  • 无论使用何种方式构造子类的对象时,都会自动调用父类的无参构造方法,来初始化父类中继承的成员变量,相当于在构造方法的第一行添加代码 super() 效果。
  • 子类一定是一个父类
public class Worker extends Person{}

方法重写原则

  • 要求方法名相同,参数列表相同以及返回值类型相同,java5开始允许返回子类类型
  • 要求方法的访问权限不能变小,可以相同或变大
  • 要求方法不能排除更大的异常(异常机制)

方法重载的执行次序

/*
1.静态代码块
2.构造块
3.构造方法体
*/


/*
1.父类的静态代码块
2.子类的静态代码块
3.父类构造块
4.父类构造方法
5.子类构造块
6.子类构造方法
*/

5.13、多态的概念


  • 同一种事物表现出来的多种形态
  • 多态引用方法,编译阶段调用父类方法,运行阶段调用子类的方法
  • 当父类类型的引用指向子类类型对象时,父类类型的引用可以调用父类中独有的方法
  • 当父类类型的引用指向子类类型对象时,父类类型的引用不能直接调用子类类型的独有方法
  • 对父子类都有的非静态方法,编译阶段调用父类,运行阶段调用子类的重写版本
  • 对父子类都有的静态方法,编译阶段和运行阶段都调用父类
  • 引用类型的转化必须发生在父子类之间
5.13.1、多态语法形式

/*
父类类型  引用变量名 = new 子类类型()
*/
Shape sr = new Rect  // getlen() 子类方法
((Rect) sr).getLen();  // 使用父类强制调用子类的独有方法, 将sr 类型强制转换为 子类类型

多态案例

/*
实现Shape类封装,特征有:横纵坐标,要求提供打印所有特征的方法
编程实现 Rect 类的封装并继承自Shape类,特征:长度和宽度
实现编程 ShapeTest 类,可以根据传入特征打印特征(矩形、圆形等等)
*/

public class ShapeTest {
	
    public static void draw(Rect r){
        r.show();
    }
	public static void draw(Circle r){
        r.show();
    }

	// 此处形成多态(多态顶替上面的 draw)
	public static void draw(Shape r){
        r.show();
    }

    public static void main(String[] args){
        // Rect r = new Rect(1,2,3,4)
        ShapeTest.draw(new Rect(1,2,3,4));
        ShapeTest.draw(new Circle(1,2,3,4));
    }
}

抽象方法/抽象类 abstract

  • 抽象方法 : 不能具体实现的方法并且用abstract 关键字修饰,也就是没有 方法体
  • 抽象类 :不能具体实例化的类(不能实例化),需要用abstract关键字修饰
  • 抽象类中可以有抽象方法,也可以 没有
  • 只有抽象类才能包含抽象方法
  • 抽象类的实际意义在于被继承,实现多态。
  • 抽象类的继承需要重写抽象类中的方法,或用抽象类继承抽象类的方式来实现
// 具体格式
/*
访问权限  abstract  返回值类型  方法名(参数列表);
*/
public abstract void cry();  // 抽象方法(宠物的叫声)

//抽象类 -不能 new对象
public abstract class AbatractTest{
	// 定义成员变量、变量封装、初始化方法
	
	// 自定义抽象方法
	public abstract void show();
	
	public static void main(String[] args){
	}
}

抽象类的应用

/*
银行有定期账户和货期账户,继承自账户类,账户类中
*/
public abstract class Account {
    private int money;
    public Account() {
    }
    public Account(int money) {
        this.money = money;
    }
    public int getMoney() {
        return money;
    }
    public void setMoney(int money) {
        if (money>0){
            this.money = money;
        }else{System.out.println("您输入的金额不正确");}
    }
    // 自定义抽象方法
    public abstract double getLixi();
}



public class FixedAccount extends Account{

    public FixedAccount(int i) {
        super(i);
    }

    @Override
    public double getLixi() {
        return getMoney();
    }

    public static void main(String[] args){
        Account acc = new FixedAccount(1000);
    }
}

引用数据类型之间的转化

  • 若强转的目标类型并不是该引用真正指向的类型数据时,则编译通过,否则运行阶段发生类型转化异常
  • 为避免发生上述错误错误,应该在强转化之前进行判断 - 用此判断 if(引用变量 instanceof 数据类型)
  • 判断引用变量指向的对象是为后面的数据类型

5.14、接口概念


  • 接口就是一种比抽象类还抽象的类,体现在所有方法都是抽象方法
  • 定义类的关键字为 class, 而定义 接口的关键字是 interface
  • 接口支持多继承
public interface InterfaceTest{
	/* pulic static final */  int CNT = 1  //里面只能有常量
	public abstract void show(); //里面只能有抽象方法,不能有方法体(新特性除外)
}
5.14.1、接口的多实现

// 金属接口
public interface Metal{
	// 自定义抽象方法描述发光行为
	pulic abstract void shine();
}


// Money 接口
public interface Money{
	// 自定义购物行为
	pulic abstract void buy();
}


// 黄金类实现前面个两个接口功能
// 使用 implements 关键字表达实现关系,支持多实现
public class Gold implements Metal,Money{
	// 重写接口的方法
	@Override
	public void shine(){
		System.out.println("发光")  
	}

	@Override
	public void buy(){
		System.out.println("买了好吃的") 
	}

	public static void main(String[] args){
		// 声明接口类型引用指向实现类的对象,形成多态
		Metal mt = new Gold();
		mt.shine();

		Money mn = new Gold();
		mn.buy();
	}
}



public interface Runner{
	// 自定义奔跑的行为
	pulic abstract void buy();
}

// 接口只能继承接口不能继承类
public interface Hunter extends Runner{
	// 自定义成员方法描述捕猎行为
	public abstract void hunt();
}

// 接口的实现 关键字  implements
public class Man implements Hunter{
	@Override
	public void hunt(){
		System.out.println("追赶小白兔")}

	@Override
	public void run(){System.out.println("正在奔跑") }

	/*
	java8之后只增接口中可增加默认方法
	默认的重写方法(default关键字)
	增加静态方法,隶属 接口层级,通过接口名直接调用
	*/
	public default show1(){
	}

	// 增加静态方法,隶属于类层级,也就是接口层级
	public static void test(){
		System.out.println("静态方法,可直接通过接口名.的方式调用,省略对象的创建")
	}

	
	public static void main(String[] args){
		// 声明接口类型的引用指向实现类的对象,形成多态
		Runner runner = new Man();
		runner.run();

		Hunter hunter =  new Man();
		hunter.hunt();

		// 使用接口名称的方式调用接口的静态方法
		hunter.test();
	}
}
5.14.2、接口和抽象类的区别

  • 定义抽象类的关键字是 abstract class , 而定义接口的关键字是 interface
  • 继承抽象类关键字是 extends, 而实现接口的关键字是 implements.
  • 继承只能单继承,而接口可以多实现
  • 抽象类中可以有构造方法,变量,而接口中不可以有构造方法,只能有常量。
  • 抽象类中可以有成员方法,而接口中只可以有抽象方法
  • 抽象类中增加方法时子类可以不用重写,而接口中增加方法时实现类需要重写
  • 接口允许出现非 抽象方法和静态方法,但非抽象类需要使用 default 关键字修饰
  • java9 开始新增加特性,接口允许出现私有化方法

5.15、内部类的概念


  • 当类定义出现另外一个类的类体中时,那么这个类叫做内部类(Inner),而这个内部类所有的类叫做外部类(Outer)
  • 类中的内容 : 成员变量、成员方法、构造方法、静态成员、构造块和静态代码块、内部类。
  • 内部类的价值 : 只为一个类服务,外部不可见,可以方便的访问外部的私有成员而不需要提供共有的get 和set 方法
5.15.1、内部类的分类

  • 普通内部类 - 直接将一个类的定义放在另外一个类的类体中
  • 静态内部类 - 使用static 关键字修饰内部类,隶属于类层级
  • 局部内部类 - 直接将一个类的定义在方法体的内部时
  • 匿名内部类 - 指没有名字的内部类
5.15.1.1、普通(成员)内部类

/**
普通内部类和普通类一样可以定义成员变量,成员方法,构造方法等
普通内部类和普通类一样可以使用 final或者 abstract关键字修饰
普通内部类还可以使用private 或 pritected关键字进行修饰
普通内部类需要使用内部类对象来创建
如果内部类访问外部类中与本类内部同名的成员变量或方法时,需要使用this关键字
*/

pubic class NormalOuter{
	private int cnt = 1;
	// 定义内部类
	public class NormalInner{
		private int ia =2;

		public NonmalInner(){
			System.out.println("普通内部类的构造方法")
		}

		public void show(){
			// 调用外部类的成员变量
			System.out.println("外部类中变量cnt的数值为" + cnt)
			System.out.println("ia" + ia)
		}

		public void show2(int cnt){
			System.out.println("形参变量 cnt=" + cnt)  // 局部优先原则
			System.out.println("内部类中 cnt=" + this.cnt)  //  打印内部类中的 cnt变量
			System.out.println("外部类中 cnt=" + NormalOuter.this.cnt)  // 局部类中的 cnt变量
		}
	}
}


// 内部类方法的调用
public class NormalOutTest{
	public static void main(String[] args){
		// 先创建外部类
		NormalOuter no = new NormalOuter();
		// 内部类指向内部对象
		NormalOuter.NormalInner ni = no.new NormalInner();
		ni.show();
	}
} 
5.15.1.2、静态内部类

  • 加入static关键字后,变成类层级,调用 用 类点 的形式调用
  • 静态方法只能访问静态成员变量
  • 静态内部类不能访问外部类的非静态成员
  • 静态内部类可以直接创建对象
public class StaticOuter{
	private int cnt = 1;   // 隶属于对象层级
	private static int snt =2;   // 隶属于类层级

	// 定义静态内部类
	public static class StaticInner{
		private int ia = 3;
		private static int snt = 4;

		public StaticInner(){
			System.out.println("静态内部类的构造方法!");
		}

		public void show(){
			System.out.println("ia = " + ia);
			System.out.println("外部类中的snt = " + snt);
		}

		// 使用不同位置的参数
		public void show2(int snt){  //就近原则
			System.out.println("snt = " + snt);   // 调用外部传递过来的
			System.out.println("内部类成员 snt = " + StaticTnner.snt);   // 内部类的参数
			System.out.println("外部类成员 snt = " + StaticOuter.snt);   // 外部类中的参数
		}
	}
}



// 内部类方法的调用
public class StaticOuterTest{
	public static void main(String[] args){
		// 无需创建外部类直接 创建内部类即可
		StaticOuter.staticInner si = new StaticOuter.staticInner();
		si.show();
	}
} 
5.15.1.3、局部内部类

  • 将类写在方法体的内部的类
访问修饰符  class  外部类的类名{
	访问修饰符  返回值类型	成员方法名(形参列表){
		class	内部类的类名{
			内部体的类体;
		}
	}
}
public class AreaOuter{
	private int cnt =1;

	public void show(){
	
		// 定义局部内部类,只在当前的方法体的内部可用
		class AreaInner{
			private int ia = 1;
			
			public AreaInner(){
				System.out.println("局部内部类的构造方法");
			}

			public void test(){
				System.out.println("ia =" + ia);
				System.out.println("cnt =" + cnt);
			}
		}
		
		// 声明局部内部类的引用指向局部内部类的对象
		AreaInner ai = new AreaInner();
		ai.test();
	}
}


// 运行调用
public class AreaOuter{
	public static viod main(String[] args){
		// 声明 外部类类型的引用指向外部类的对象
		AreaOuter ao = new AreaOuter();
		// 通过show 方法调用实现局部内容类的定义和使用
		ao.show();
	}
}
5.15.1.4、局部内部类的使用方式

  • 局部内部类只能在该方法的内部使用
  • 局部内部类可以 在方法体内部直接创建对象
  • 局部内部类不能使用 访问控制符和 static 关键字修饰符
  • 局部内部类 可以使用外部方法的局部变量,但是必须是final的。由局部内部类 和局部变量的声明周期不同所致
5.15.1.5、回调模式

  • 回调模式 — 如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中 所有实现的方法(接口中定义的)
// 定义一个接口
public interface AnonymousInterface{
	// 自定义接口的抽象方法
	public abstract void show();
}

// 实现接口的类
public class AnonymousInterfaceImpl implements AnonymousInterface{
	@Override
	public void show(){
		System.out.println("这是接口的实现类")
	}
}


public class AnonymousInterfaceTest{
	// 假设已有下面方法
	public static void test(AnonymousInterface ai){
		ai.show();
	}

	public static void main(String[] args){
		//  AnonymousInterface ai = new AnonymousInterfaceImpl()
		AnonymousInterfaceTest(new AnonymousInterfaceImpl());
	}
}
5.15.1.6、匿名内部类

  • 当接口/类类型的引用作为方法的形参时,实参的传递方式有两种
  • 自定义类实现接口/继承类并重写方法,然后创建该类对象作为实参传递
  • 使用上述匿名内部类的语法格式得到接口/类类型的索引即可

匿名内部类的语法格式

接口/父类类型	引用变量名 = new 接口/父类类型(){ 方法的重写 }
public class AnonymousInterfaceTest{
	public static void test(AnonymousInterface ai){
		ai.show();
	}

	public static void main(String[] args){
		AnonymousInterfaceTest.test(new AnonymousInterfaceImpl());

		AnonymousInterface ait = new AnonymousInterface(){
			@Override
			public void show(){
				System.out.println("这里是接口的实现类");
			}
		}
		
		// 从java8 开始提出新特性 lamda 表达式可以简化上述代码,格式为:(参数列表)->{方法体}
		AnonymousInterface ait =() -> System.out.println("lamda 表达式原来是如此简单")
		AnonymousInterfaceTest.test(ait2);
	}
}

5.16、枚举定义


  • 使用 public static final 表示的常量描述 较为繁琐,使用 enum关键字来定义枚举类型取代常量,美剧类型是从java5 开始增加的一种引用数据类型
  • 枚举值就是当前类的类型,也就是指向本类的对象,默认使用public static final 关键字共同修饰,因此采用枚举类型 . 的方式调用。
  • 枚举类可以自定义构造方法,但是构造方法的修饰符必须是private, 默认也是私有的
/*
编程实现所有方向的枚举,所有的方向,向上,向下,向左,向右  枚举类型要求所有枚举必须放在枚举类型的最前面
*/
public enum DirectionEnum{
	// 声明本类类型的引用指向类类型的对象,需要放在最前面
	UP(desc:"向下"),DOWN(desc:"向下"),LEFT(desc:"向左"),RIGHT(desc:"向右");
	private final String desc; // 用于描述方向字符串的成员变量
	
	private DirectionEnum(String desc){
		this.desc = desc;
	}

	// 通过公有的get方法可以在本类的外部访问该类成员变量的数值
	public String getDesc(){
		return desc;
	}
}



// 枚举类型的调用
public class DirectionTest{
	public static void mian(String[] args){
	DirectionEnum de = DirectionEnum.DOWN;
	System.out.println("方向为:" + de.getDesc());
	}
5.16.1、枚举类型

public class Direction{
	// final 修饰成员变量,必须初始化,且不能改变
	private final String desc; // 用于描述方向字符串的成员变量

	// 通过构造方法实现成员变量的初始化,更加灵活
	public Direction(String desc){
		this.desc = desc;
	}

	// 1.为了不让外部不能随意的调取构造方法,所以进行私有化
	private Direction(String desc){
		this.desc = desc;
	}

	// 2.声明本类类型的引用指向本类类型的对象
	public static final Direct UP = new Direction(desc:"向上");
	public static final Direct DOWN = new Direction(desc:"向下");
	public static final Direct LEFT = new Direction(desc:"向左");
	public static final Direct RIGHT = new Direction(desc:"向右");
	
	// 通过公有的get 方法可可以在本类的外部访问该类成员变量的数值
	public String getDesc(){
		return desc;
	}
}



public class DirectionTest{
	public static void mian(String[] args){
		// 声明Direction类型的引用指向该类型的对象并打印特征
		Direction d1 = new Direction(desc:"向上");
		System.out.println("获取到字符串是:" + d1.getDesc()); // 向上

		Direction d2 = new Direction(desc:"向下");
		System.out.println("获取到字符串是:" + d2.getDesc()); // 向下

		Direction d3 = new Direction(desc:"向左");
		System.out.println("获取到字符串是:" + d3.getDesc()); // 向左

		Direction d4 = new Direction(desc:"向右");
		System.out.println("获取到字符串是:" + d4.getDesc()); // 向右

		Diretion d5 = Direction.UP;
		System.out.println("获取到的方向是" + d1.getDesc());  // 向上

	}
}
5.16.2、自定义类和枚举类型使用的区别

public class DirectionUseTest{

	// 自定义静态方法实现根据参数指定的字符串内容,打印具体的方向信息
	public static void test(String str){
		switch(str){
			case "向上"System.out.println("向上的部分");break;
			case "向下"System.out.println("向下的部分");break;
			case "向左"System.out.println("向左的部分");break;
			case "向右"System.out.println("向右的部分");break;
			default:
				System.out.println("没有这样的方法")		
		}
	}


	public  static void test2(DirectionEnum de){
		switch(de){	
			case UP:
				System.out.println("向上的部分");break;
			case DOWN:
				System.out.println("向下的部分");break;
			case LEFT:
				System.out.println("向左的部分");break;
			case RIGHT:
				System.out.println("向右的部分");break;
			default:
				System.out.println("没有这样的方法")	
			
		}
	}
	
	public static void main(String[] args){
		DirectionUserTest.test1(Direction.UP.getDesc());

		DirectionUseTest.test2(DirectionEnum.DOWN);
	}
}
5.16.3、Enum类的概念和方法

  • 所有的枚举类都默认继承自 java.lang.Enum类,常用方法如下
方法方法解析
static T[] values()返回当前枚举类中的所有对象
String toString()返回当前枚举对象的名称
int ordinal()获取枚举对象在枚举类中的索引位置
static T valueOf(String str)将参数指定的 字符串名转为当前枚举类的对象
int compare To(E o)比较两个枚举对象在定义时的 顺序
注: T 是type 的首字母
public class DirectionEnumTest{
	public static void main(String[] args){
	
		//1.获取 DirectionEnum 类型中所有的枚举对象
		DirectionEnum[] arr = DirectionEnum.values();
		//2.打印每个枚举对象在枚举类型中的名称和索引位置
		for(int i =2;i<arr.length;i++){
			System.out.println("获取的枚举对象名称是" + arr[i].toString());
			System.out.println("获取的枚举对象对应的索引位置是" + arr[i].ordinal());
		}

		// 3.根据参数指定的字符串得到枚举类型的对象,也就是将字符串转换成对象
		DirectionEnum de = DirectionEnum.valueOf("DOWN");
		System.out.println("转换出来的枚举对象名称是" + de.toString());
		
		// 可以不写 de.toString 当打印引用变量是,回自动调用 toString 方法
		System.out.println("转换出来的枚举对象名称是" + de);

		for (int i =0;i<arr.length;i++){
			// 当调用对象在参数对象之后时,获取到的比较结果为 正数
			// 当调用对象在参数对象相同位置时,获取到的比较结果为 0
			// 当调用对象在参数对象之前位置时,获取到的比较结果为 负数
			System.out.println("调用对象与数组中对象比较先后顺序结果是:" + de.compareTo(arr[i]))
		}
	}
}
5.16.4、枚举类型实现接口

  • 枚举类实现接口后需要重写抽象方法,而重写方法的方式有两种:重写一个,或每个对象都重写
  • 枚举每个对象都重写 是匿名
// 定义一个接口
public interface DirectionInterface{
	// 自定义抽象方法
	public absrtact void show();
}

public enum DirectionEnum implements DirectionInterface{
	// 声明本类类型的引用指向类类型的对象
	UP(desc:"向上"),DOWN(desc:"向下"),LEFT(desc:"向左"),RIGHT(desc:"向右")

	// 每个对象都重写
	UP(desc:"向上"){
		@Override
		public void show(){}
	}

	private final String desc; // 用于描述方向字符串的成员变量
	
	private DirectionEnum(String desc){
		this.desc = desc;
	}

	public String getDesc(){return desc;}

	// 重写接口中的方法(整个枚举类型重写一次,所有对象调用同一个)
	@Override
	public void show(){
		System.out.println("此处重写了接口中的show方法");
	}
}

5.17、注解的概念


  • 注解又叫标注,是从java5开始增加的一种引用引用数据类型
  • 注解 本质上就是代码中特殊标记,通过这些标记可以在编译阶段、类加载阶段、以及运行时执行指定的处理
  • 自定义注解自动继承 java.lang.annotation.Annotation接口
  • 通过@注解名称的方式可以 修饰包、类、成员方法、成员变量、构造方法、参数、局部变量的声明
  • 注解体中只有成员变量没有成员方法,而注解的成员变量以"无形参的方法"形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型
  • 注解的成员类型

注解的语法格式 - 实际上注解是一种特殊的接口

访问修饰符 @interface 注解名称{
	注解成员;
}

// 注解(若一个注解中没有任何成员,则这样的注解叫做标记注解/标识注解)
public @interface MyAnnotation{
}

// 注解的使用,表示将标签 MyAnnotation贴到person上
@MyAnnotation
public class Person{}

// 注解中定义成员变量
public @interface MyAnnotation{
	public String value(); // 声明一个 String类型的成员变量,名字为 value
	public String value2();
	// 若注解中成员变量使用时不给值,则需要使用default关键字,给一个默认值
	public String value() default "123";
}

// 注解的使用,注解函数中有成员变量,赋值
@MyAnnotation(value="hello",value2="world")
public class Person{}

5.18、元注解


  • 可以注解到注解上的注解,或者说元注解是一种基于注解,但是它能够应用到其他注解上面
  • @Retention - 描述注解的范围,及有效周期
  • @ Documented - 注解是否在文档描述中体现
  • @ Target - 注解到底 可以修饰哪些内容
  • @Inherited - 注解是否可以被继承到所标记类的子类中
  • @ Repeatable - 是否可以重复
/*
元注解
RetentionPolicy.SOURCE 注解只有在源码阶段保留,在编译器进行编译时它被丢弃
RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到JVM中,默认方式。
*/

6、JAVA常用核心类库


  • java.lang - 核心包,所有 内容由虚拟机自动导入。如 : System类、String类。
  • java.util包 - 工具包、提供大量的工具类及集合类。 如 Scanner类、Random类、List 集合。
  • java.io包 - 输入输出包,包含大量的读写文件相关的类。 如:FileInputStream类、FileOutputSteam类。
  • java.net包 - 网络包 ,提供大量网络编程相关的类。如 : ServerSocket类、Socket类。
  • java.sql包 - 数据包,提供大量操作数据库的类和接口。如:DriverManager类、Connection接口

6.1、java.lang 包

// equals 方法的重写
@Override
public boolean equals(Object obj){
	// 调用对象和参数对象指向通一对象(地址),则内容一定相同
	if(this == object) return true; 
	// 调用对象不为空,参数对象为空,则内容一定不相同
	if(null == obj) return false;
	// 判断 参数obj 指向对象是否为 Student类型对象,若是则条件成立,否则条件不成立
	if(obj instanceof Student){
		Student ts = (Student) obj;
		return this.getId() == ts.getId();
	}
	return false;
}

// 重写 hashCode 方法(重写 equals 就需要重写 hashcode)
@Override
public int hashCode(){
	return getId();
}

// String toString  获取调用对象的字符串形式    包名.类名@哈希码值得十六进制

6.2、java.date 包

public class dataTest {
    public static void main(String[] args) {
        // 当前系统时间
        Date d1 = new Date();
        System.out.println("d1 = " + d1);

        // 获取对象距离1970年1月1日0点0分0秒的毫秒数
        Date d2 = new Date(1000);
        System.out.println("d2 = " + d2);

        // 3.获取调用对象距离1970年1月1日0时0分0秒的毫秒数
        long mesc = d2.getTime();
        System.out.println("获取d2到1970的毫秒数为" + mesc);

        //4、设置调用对象的时间点
        d2.setTime(2000);
        System.out.println("修改后的时间为" + d2);
    }
}



import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatTest {
    public static void main(String[] args) throws Exception {
        //1.获取系统当前时间
        Date d1 = new Date();
        System.out.println("d1 =" + d1 );
        //2.构造SimpleDateFormat类型的对象并指定格式
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //3.实现日期格式向文本类型的转换并打印
        //alt + Enter 可以实现返回值的生成
        String format = sdf.format(d1);
        System.out.println("转换后的日期为" + format);
        //4.实现文本类型到日期类型的转化打印
        Date parse =sdf.parse(format);
        System.out.println("转化日期格式的结果为" + parse);
    }
}



import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

public class CalendarTest {
    public static void main(String[] args) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //1.使用指定的时间来构造对象
        Calendar instance = Calendar.getInstance();
        //2.设置日期对象的格式及打印
        instance.set(2008,8,8,20,8,8);
        //3.转化为DATE类型的对象
        Date d2 = instance.getTime();
        String format1 = sdf.format(d2);
        System.out.println("获取到的时间为" + format1);

        // 向指定的字段是指或增加数值
        instance.set(Calendar.YEAR,2018);
        Date d3 = instance.getTime();
        System.out.println("设置后的年份结果为" + sdf.format(d3));
        
        instance.add(Calendar.MONTH,2);
        Date d4 = instance.getTime();
        System.out.println("设置后的年份结果为" + sdf.format(d4));
    }
}

6.3、集合


  • 记录多类型不同得对象数据,称之为集合

  • java.util.Collection 集合 (单个元素)

  • java.util.Map 集合 (字典格式)

  • 在这里插入图片描述

方法声明功能介绍
boolean add()向集合中添加元素
boolean addAll(Collection)将参数集合中得所有元素添加到调用集合中
boolean contains(Object o)判断是包含
boolean containsAll(Collection)判断调用集合是否包含参数集合
boolean retainAll(Collection))保留两个集合得公共部分,交集
boolean remove(Object o)从集合中删除
boolean removeAll((Collection)删除集合中指定得所有对象
void clear()清空集合
int size()返回集合对象个数
boolean isEmpty()判断集合是否为空
boolean equals(object o)判断是否相等
int hashCode()获取当前集合得哈希码值
object[] toArray()将集合转换为数组
Iteratoriterator()获取当前集合得迭代器
6.3.1 Iterator接口

  • java.util.lterator接口用于描述 迭代器对象,可以遍历Colletction集合的所有元素
  • java.util Collection 接口继承 lterator接口,因此所有实现Collection接口类都可以使用迭代器对象
方法声明功能介绍
boolean hasNext()判断集合中是否有可以迭代/访问的元素
E next()用于取出一个元素并指向下一个元素
void remove()用于删除访问到的最后一个元素
import sun.plugin.javascript.navig.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Objects;

public class CollectionTest {
    public static void main(String[] args){
        // Collection c1 = new Collection();  此语句无效,因为 Collection 为接口,不能创建对象
        Collection c1 = new ArrayList();
        boolean b1 = c1.add(new String("one"));
        System.out.println("集合中的元素为" + c1);

        b1 = c1.add(Integer.valueOf(2));
        System.out.println("b1 =" + b1);
        System.out.println("集合中的元素为" + c1);

        b1 = c1.add(new Person("张飞",30));
        System.out.println("集合中的元素为" + c1);  // 集合中的元素为[one, 2, Person{name='张飞', age=30}]

        Collection c2 = new ArrayList();
        c2.add("three");
        c2.add(4);
        System.out.println("集合中的元素为" + c2);  //集合中的元素为[three, 4]

        c1.addAll(c2);
        System.out.println("集合中的元素为" + c1);   // 集合中的元素为[one, 2, Person{name='张飞', age=30}, three, 4]

        // 判断是否包含单个元素
        b1 = c1.contains("one");
        System.out.println("集合中的元素为" + b1);

        b1 = c1.contains(8);
        System.out.println("集合中的元素为" + b1);

        // contains 通过equal 来判断是否包含,此处new中内有重写 equal所以判断为地址,需要重写equals
        b1 = c1.contains(new Person("张飞",30));
        System.out.println("集合中的元素为" + b1);

        // 判断是否包含参数指定集合的所有
        Collection c3 = new ArrayList();
        c3.add(4);
    
        b1 = c1.containsAll(c3);  // c1 中是否包含c3的全部元素   true


        // 计算两个集合的交集,如果当前集合改变则返回true,如果没改变则返回flase
        b1 = c2.retainAll(c2);

        // 计算 c2、c3的交集并保留在集合 c2中,取代c2中原有的数值
        b1 = c2.retainAll(c3);
        System.out.println(b1);
        System.out.println(c2);   // 此时c2已经发生改变,变成了 交集


        // remove 方法原理equals
        // 从集合中删除单个元素
        b1 = c1.remove("one");
        b1 = c1.remove(new Person("张飞",30));
        System.out.println(b1);
        System.out.println(c1);

        // 从集合c1 中删除 集合 c3中的全部元素,c1 方法改变
        b1 = c1.removeAll(c3);

        // 清空集合
        c3.clear();
        System.out.println(c3);
        // 判断集合元素个数
        System.out.println(c1);
        System.out.println(c1.size());
        c1.isEmpty();   // 判断是否为空


        // 集合转化成数组
        Object[] objects = c2.toArray();
        System.out.println("数组中元素有" + Arrays.toString(objects));

        // 数组类型向集合类型的转化
        Collection objects1 = Arrays.asList(objects);

        // 获取当前集合的迭代器
        Iterator iterator1 = c1.iterator();
        System.out.println(iterator1.hasNext());
        System.out.println(iterator1.next());   


		
		//使用迭代器来模拟toString方法的打印效果
		// 由于上个循环已经使得迭代器走到了最后,因此需要重置迭代器
        iterator1 = c1.iterator();
      
        StringBuilder sb1 = new StringBuilder();
        sb1.append("[");
        while (iterator1.hasNext()){
            Object obj = iterator1.next();
            // 当获取元素是最后一个元素时,则拼接元素加括号
            if(!iterator1.hasNext()){
                sb1.append(obj).append("]");
            }else{
                sb1.append(obj).append(",").append(" ");
            }

        }
        System.out.println("c1=" + sb1);  //  c1=[2, Person{name='张飞', age=30}, three]


		// 不断得获取集合中得元素并判断,当元素值"ONE",时,则删除该元素
		iterator1 = c1.iterator();
        while (iterator1.hasNext()){
            Object obj = iterator1.next();
            if ("one".equals(obj)){
                iterator1.remove();
            }
        } 

         // 使用 for eachxun循环遍历数和集合
        // for(元素类型  变量名 : 数组/集合名称) {循环体}
        for (Object obj : c1){
            System.out.println("取出来得元素时" + obj);
        }
    }
}

7、异常处理机制

  • java.lang.Throwable 类是错误(Error)和异常(Exception)的超类
  • Exception 主要包括 运行时异常(RuntimeException)和检测性异常(IOException)

RuntimeException

  • ArithmeticException 类 - 算数异常
  • ArrayIndexOutOfBoundException类 - 数组下标越界异常
  • NullPointerException -空指针异常
  • ClassCastException - 类型转换异常
  • NumberFormatException - 数字格式异常
import java.io.IOError;
import java.io.IOException;

public class ExceptionPreventTest {
    public static void main(String[] args) {
        // 非检测性异常,运行时异常
        //System.out.println(5/0);

        //检测性异常
        //Thread.sleep(1000);
        System.out.println("程序结束");

        // 空指针异常
        String str = null;
        if(null!= str){
            System.out.println(str.length());
        };

        // 类型转化异常
        Exception ex = new Exception();
        if(ex instanceof IOException){
            IOException ie = (IOException)ex;
        };

7.1、异常捕获


ctrl + alt + t
/*
try{
编辑可能发生异常代码
} catch(异常类型 引用变量名){
	编写针对该异常处理代码
	}
	finally{
		编写无论发生什么都会执行的代码
	}
*/
public class ExceptionCatchTest {
    public static void main(String[] args) {

        //创建一个fileinputstream 类型的对象,与demo/a.text关联
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(".demo/a.text");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 关闭文件
        try {
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            System.out.println("最后一句");
        }
    }
}

7.2、异常抛出


import java.io.IOException;

public class ExceptionMethod {
    public void show() throws IOException{}
}



import java.io.FileNotFoundException;
import java.io.IOException;

public class SubExcetionMethod extends ExceptionMethod{

    @Override
    // 子类重写的方法可以抛出和父类一样的异常
    // 子类重写的方法可以抛出更小的异常
    // 子类可以不抛出异常
    // 不可以抛出平级不一样的异常
    // 不可以抛出更大的异常
    public void show() throws FileNotFoundException {}
}

7.3、自定义异常


// 定义年龄异常类
public class AgeException extends Exception{

    static final long serialVersionUID = 7837261718L; // 序列化版本号

    public AgeException() {
    }

    public AgeException(String message) {
        super(message);
    }
}
// 定义person 类
public class Person {

    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) throws AgeException {
        setAge(age);
        setName(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }
// 测试类
public class PersonTest {

    public static void main(String[] args) {

        Person p1 = null;
        try {
            p1 = new Person("zhangfei",-30);
        } catch (AgeException e) {
            e.printStackTrace();
        }
        System.out.println("p1="+p1);
    }
}

8、JAVA File类


  • 基本概念 :java.io.File 类主要用于描述文件或目录路径的抽象表示信息,如大小
import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class FileTest {

    // 实现成员方法实现 指定目录及子目录中所有内容的打印

    public static void show(File file){
        // 获取目录 f3 下的所有内容并记录到一维数组中
        File[] filesArray = file.listFiles();    // 获取该目录下的所有内容
        // 遍历数组
        for(File tf:filesArray){
            // 判断是否为文件
            if(tf.isFile()){
                System.out.println(tf.getName());
            }
            // 判断是否为文件夹
            if(tf.isDirectory()){
                System.out.println("[" + tf.getName() + "]");
                show(tf);
            }
        }

    }


    public static void main(String[] args) throws IOException {
        
        
        // 1.构造 File类型的对象 与 d:a.txt 文件关联
        File f1= new File("d:a.txt");
        // 2.若文件存在则获取文件相关信息并打印 后删除文件
        if(f1.exists()){
            System.out.println("文件的名称是" + f1.getName());
            System.out.println("文件的大小为" + f1.length());

            // System.out.println("文件最后一次的修改时间" + f1.lastModified());    返回时间戳
            Date d1 = new Date(f1.lastModified());  // 转化为时间
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm;ss");   // 修改时间格式
            System.out.println("文件最后一次的修改时间" + sdf.format(d1));

            System.out.println("文件的绝对路径信息是" + f1.getAbsolutePath());
            System.out.println(f1.delete()? "文件删除成功": "文件删除失败");
        } else{
            // 3. 若文件不存在则创建新的文件夹
            // 此处异常,抛出
            System.out.println(f1.createNewFile()? "文件创建成功": "文件创建失败");
        }

        System.out.println("---------------------");

        //4.实现目录的删除与创建
        File f2 = new File("d:/目录1");
        if(f2.exists()){
            System.out.println("目录的文件名是" + f2.getName());
            System.out.println(f2.delete()? "目录删除成功": "目录删除失败");    // 删除最后一级目录
        } else {
            System.out.println(f2.mkdir()? "目录创建成功": "目录创建失败");    // 创建单级目录
            System.out.println(f2.mkdirs()? "目录创建成功": "目录创建失败");   // 创建多级目录
        }

        System.out.println("---------------------");

        // 5.打印目录下的所有内容
        File f3 = new File("d:/目录1");

        // 获取目录 f3 下的所有内容并记录到一维数组中
        File[] filesArray = f3.listFiles();    // 获取该目录下的所有内容
        // 遍历数组
        for(File tf:filesArray){
            // 判断是否为文件
            if(tf.isFile()){
                System.out.println(tf.getName());
            }
            // 判断是否为文件
            if(tf.isDirectory()){
                System.out.println("[" + tf.getName() + "]");

            }
        }

        // 6.实现目录中素有内容获取的同时进行过滤
        // 匿名内部类的语法格式 :接口/父类类型 引用变量名 = new 接口/父类类型(){方法重写};
        FileFilter fileFilter = new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                // 若文件名以 avi 结尾 则返回
                return pathname.getName().endsWith(".avi");
            }
        };

        File[] filesArray2 = f3.listFiles(fileFilter);
        for(File tf:filesArray2){
            System.out.println(tf);
        }


        // 7.使用递归思想 获取目录并打印文件名
        show(new File("d:/目录1"));
    }
}


9、JAVA IO流


基本概念

  • IO = Input + Output, 即为输入和输出
  • 分为字节流 和 字符流
  • 字节流可以书写任意形式的数据
  • 字符流只能以字符(2字节)为单位进行书写,只能读写 文本文件

在这里插入图片描述

9.1、FileWrite类


  • 将文本内容写入到文本文件
import java.io.FileWriter;
import java.io.IOException;

public class FileWriterTest {
    public static void main(String[] args) {

        FileWriter fw = null;

        try {
            // 1.构造 FileWrite 类型的对象 与 文件关联
            // 若文件不存在,则自动进行创建
            // 若文件存在 则清空原文件内容
            // fw = new FileWriter("d:/a.txt", append:true);    追加写入方式
            fw = new FileWriter("d:/a.txt");


            // 2.通过流 对象写入数据内容
            fw.write("a");

            // 写入字符数组中的内容
            char[] cArr = new char[]{'h','e','l','l','o'};
            fw.write(cArr,1,3);   // 写入部分
            fw.write(cArr);   // 写入全部

            //刷新流
            fw.flush();

            System.out.println("数据写入成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 3. 关闭流对象并释放有关资源
            if(null!=fw){
                try {
                    fw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9.2、FileReader类


  • 文本文件的读取
import java.io.FileReader;
import java.io.IOException;

public class FileReaderTest {
    public static void main(String[] args) {
        FileReader fr = null;
        try {
            // 1.构造 FileReader类型的对象 与文件关联
            fr = new FileReader("D:/目录1");


            /*
            // 2.读取文件内容并打印,返回内容为字符的 ARSC码值需要转化
            int res = fr.read();
            System.out.println("读取到的单个字符是" + (char)res);
            */


            /*
            // 读取全部内容
            int res =0;
            while ((res = fr.read()) != -1){
                System.out.println("读取到的单个字符是" + (char)res);
            }
            */


            /*
            // 读取数组
            char[] cArr = new char[5];
            int res = fr.read(cArr,1,3);
            System.out.println("实际读取到的字符个数是:" + res );
            for(char cv:cArr){
                System.out.println("读取到的字符是:" + (char)cv);
            }*/
            

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 3.关闭流对象并释放有关资源
            if (null != fw){
                try {
                    fr.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9.3、FileOutputStream类/FileInputStream类


  • 用于图像数据之间的原始字节流写入流中
  • 图片文件的拷贝
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class FileOutputStreamTest {
    public static void main(String[] args) {
        FileInputStream fis = null;
        FileOutputStream fos = null;

        try {
            // 1.创建 FileInputStream 类型的对象与图片关联
            fis = new FileInputStream("d:/图片1");
            // 2.创建 FileOutputStream 类型的对象与图片关联
            fos = new FileOutputStream("d:/图片2");
            // 3.不断读取,并写入
            System.out.println("正在拷贝中");

            
            /*
           拷贝方式 1 :
            int res = 0;
            while ((res = fis.read()) != -1){
                fos.write(res);
            }
            */


            
            /*
            //拷贝方式 2 :
            int len = fis.available();    // 获取拷贝文件的大小
            System.out.println("拷贝文件的大小是:" + len);
            byte[] bArr = new byte[len];
            int res = fis.read(bArr);
            System.out.println("实际文件的大小为:" + res);
            fos.write(bArr);
            */


            // 拷贝方式 3 :
            byte[] bArr = new byte[1024];
            int res = 0;
            while ((res = fis.read(bArr)) != -1){
                fos.write(bArr,0,res);
            }


            System.out.println("拷贝成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(null != fis){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != fos){
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9.4、BufferedInputStream / BufferedOutputStream


  • 描述缓冲输入、输出流,不用为每个字节调用底层系统
import java.io.*;


public class BufferedByteCopyTest {
    public static void main(String[] args) {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;

        try {
            //1.创建 BufferedInputStream类 与文件关联,默认 4MB
            bis = new BufferedInputStream(new FileInputStream("d:/视频1"));
            //2.创建 BufferedOutputStream类 与文件关联 默认 4MB
            bos = new BufferedOutputStream(new FileOutputStream("d:/视频2"));
            // 3.不断的读取和写入
            // 自定义缓冲区
            System.out.println("正在复制中");
            byte[] bArr = new byte[1024];
            int res = 0;
            while ((res = fis.read(bArr)) != -1){
                fos.write(bArr,0,res);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            // 4.关闭流对象
            if(null != bos){
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != bis){
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9.5、BufferedReader / BufferedWriter


  • 写入单个字符,字符数组,字符串到输出流中

import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.BufferedWriter;

public class BufferedTest {
    public static void main(String[] args) {
        BufferedReader br = null;
        BufferedWriter bw = null;
        try {
            //1.创建 BufferedReader 类型的对象 与 文件关联
            br = new BufferedReader(new FileReader("d:/a.txt"));
            // 2.创建 BufferedWriter 类型的对象 与 文件关联
            bw = new BufferedWriter(new FileWriter("d:/b.txt"));
            // 3.读取和写入
            String str = null;
            while ((str = br.readLine()) != null){
                bw.write(str);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.关闭
            if(null != bw){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != br){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9.6、PrintStream类/ PrintWrite类


  • 打印各种数据内容
  • 将对象的格式化形式打印到文本输出流
/*
不断的提示用户输入发送内容,若发送的内容 "bye" 则聊天结束,否则用户输入内容写入到文件中
要求使用BufferedReader 类来读取键盘的输入,System.in代表键盘输入
要求 使用PrintSteam 类负责讲数据写入文件
 */

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.Date;

public class PrintWriteTest {
    public static void main(String[] args) {
        BufferedReader br = null;
        PrintStream ps = null;

        try {
            // 由手册可知 : 构造方法需要是Reader类型的引用,但Reader类是一个抽象类,实参只能传递子类的对象,字符流
            // 由手册可知 : System.in 代表键盘输入,而且是 InputStream类型的 字节流
            br = new BufferedReader(new InputStreamReader(System.in));
            ps = new PrintStream(new FileOutputStream("d:/a.txt"));

            // 声明一个boolean 类型的变量作为发送方的代表
            boolean flag = true;

            while(true) {
                // 1.提示用户输入发送聊天的内容,并使用变量记录
                System.out.println("请"+ (flag? "张三" :"李四") + "输入要发送的聊天内容");

                String str = br.readLine();
                // 2.判断用户输入的内容是否为 "bye",若是则聊天结束
                if ("bye".equals(str)){
                    System.out.println("聊天结束");
                    break;
                }
                // 3. 若不是则将用户输入的内容写入到 文件中
                else{
                    Date d1 = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                    ps.println( sdf.format(d1) + (flag? "张三说" :"李四说") + str);
                }
                flag = !flag;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.关闭
            if(null != ps){
                ps.close();
            }
            if (null !=br){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9.7、DataOutputStream / DataInputStream类


  • 将基本数据类型写入输入流中
  • 从输入流中读取基本数据类型的数据
import java.io.*;

public class DataOutputStreamTest {
    public static void main(String[] args) {
        DataOutputStream dos = null;
        try {
            //1.创建DataOutputStream 类型的对象 和文件关联
            dos = new DataOutputStream(new FileOutputStream("d:/a.txt"));
            // 2. 准备一个整数数据66 并写入输入流
            int num = 66;
            dos.writeInt(num);
            System.out.println("写入数据成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 3.关闭流对象并释放有关的资源
            if(null !=dos){
                try {
                    dos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


        DataInputStream  dis = null;

        try {
            //1.创建DataInputStream 类型的对象 和文件关联
            dis = new DataInputStream(new FileInputStream("d:/a.txt"));
            // 2. 从输入流中读取一个整数并打印
            int res = dis.readInt();
            System.out.println("读取到的值为:" + res);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if(null != dis){
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

9.8、ObjectOutStream / ObjectInputStream


  • 在输入流中进行写入对象
  • 在输出流中进行读取对象
  • 写入的类对象必须实现 Serializable接口 (实现序列化功能)
public class User implements java.io.Serializable {
    private static final long serialVersionUID = 7704492997062366869L;
    private String userName;   // 姓名
    private String password;   // 密码
    private String phoneNum;    // 手机号


    public User() {
    }


    public User(String userName, String password, String phoneNum) {
        this.userName = userName;
        this.password = password;
        this.phoneNum = phoneNum;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPhoneNum() {
        return phoneNum;
    }

    public void setPhoneNum(String phoneNum) {
        this.phoneNum = phoneNum;
    }
}
import java.io.*;

public class ObjectTest {
    public static void main(String[] args) {
        ObjectOutputStream oos = null;

        try {
            //1.创建 ObjectOutputStream类型的对象,与文件相关联
            oos = new ObjectOutputStream(new FileOutputStream("d:/a.txt"));
            // 2. 准备一个User类型的对象,并初始化
            User user = new User("LCL","123456","15243245591");
            // 3.将整个USER 类型的对象写入输入流
            oos.writeObject(user);
            System.out.println("写入成功");
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.关闭,并释放资源
            if(null != oos){
                try {
                    oos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        ObjectInputStream ois = null;

        try {
            //1.创建 ObjectInputStream 类型的对象,与文件相关联
            ois = new ObjectInputStream(new FileInputStream("d:/a.txt"));
            // 2.从输入流中读取一个对象并打印
            Object obj = ois.readObject();
            System.out.println("读取到的数据为:" + obj);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if(null != ois){
                try {
                    ois.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

10、JAVA线程


创建方式

  • 自定义类继承 Thread 类,并重写run 方法,然后创建该类的对象调用 start() 方法
  • 自定义类实现 Runnable接口,并重写 run() 方法,创建该类的对象作为实参来构造 Thread类型的对象
  • 使用Thread类型的对象调用 start 方法。
  • 线程6种状态 :New(新创建)、Runnable(可运行)、Blocked(被阻塞)、Waiting(等待)、Timed Waiting(计时等待)、Terminated(被终止)、getState(获取当前线程状态)

10.1、启动方式


//创建方式 1 

public class SubThreadRun  extends Thread {

    @Override
    public void run() {
        for(int i=1;i<=20;i++){
            System.out.println("run方法中 i = " + i);
        }
    }
}


public class SubThreadRunTest {
    public static void main(String[] args) {
        Thread t1 = new SubThreadRun();
        // 启动线程,自动调用虚拟机中的 run 方法
        t1.start();

        for(int i=1;i<=20;i++){
            System.out.println("mian方法中 i = " + i);
        }
    }
}
// 创建方式2

public class subRunnableRun implements Runnable{
    @Override
    public void run() {
    	// 获取子线程的 编号和名字
    	Thread t2 = Thread.currentThread();
    	System.out.println("子线程的编号是 " + t2.getId() + "子线程的名字是" + t2.getName());
    	
        for(int i=1;i<=20;i++){
            System.out.println("run方法中 i = " + i);
        }
    }
}


public class subRunnableRunTest {
    public static void main(String[] args) {
    
        subRunnableRun srr = new subRunnableRun();
        Thread t1 = new Thread(srr);
        t1.start();

        for(int i=1;i<=20;i++){
            System.out.println("mian方法中 i = " + i);
        }
    }
}
// 创建方式 3 :匿名内部类方式实现线程

public class ThreadNoNameTest {
    public static void main(String[] args) {

        // 匿名内部类的语法格式 :父类/接口类型 引用变量名 = new 父类/接口(){方法重写};
        //1.使用继承加匿名内部类的方式创建并启动线程
        Thread t1 = new Thread(){
            @Override
            public void run(){
                System.out.println("请问在么?");
            }
        };
        t1.start();

        //2.使用实现接口加匿名内部类的方式创建 并启动线程
        Runnable ra = new Runnable() {
            @Override
            public void run() {
                System.out.println("不在呀");
            }
        };
        Thread t2 = new Thread(ra);
        t2.start();
    }
}

10.2、线程等待


public class ThreadJoinTest extends Thread {
    @Override
    public void run() {
        System.out.println("倒计时开始");
        for (int i =1;i<10;i++){
            System.out.println(i);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("新年快乐");
        }
    }

    public static void main(String[] args) {
        ThreadJoinTest tjt = new ThreadJoinTest();
        tjt.start();

        // 主线程开始等待
        System.out.println("主线程开始等待");
        try {
            // 当前线程等待
            tjt.join();
            // tjt.join(1000); 设置等待时长
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

10.3、守护线程


  • 设置守护线程需要在 线程启动前设置
  • 一旦线程结束,则守护线程随之结束
public class ThreadDaemonTest extends Thread{
    @Override
    public void run() {
        System.out.println(isDaemon()? "该线程为守护线程" :"该线程不是守护线程"); // 新建线程不是守护线程
        for(int i = 0;i<50;i++){
            System.out.println("子线程中 i =" + i);
        }
    }

    public static void main(String[] args) {

        ThreadDaemonTest tdt = new ThreadDaemonTest();
        // 必须在线程启动前设置守护线程,
        tdt.setDaemon(true);
        tdt.start();

        for(int i = 0;i<20;i++){
            System.out.println("主线程中 i =" + i);
        }
    }
}

10.4、同步代码块实现线程同步


public class AccountRunnableTest implements Runnable{
    private int balance;
    private Demo dm = new Demo();


    public AccountRunnableTest() {
    }

    public AccountRunnableTest(int balance) {
        this.balance = balance;
    }

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

    @Override
    public void run() {
        synchronized (dm) {
            // 1.后台查询账户余额
            int temp = getBalance();
            // 2.模拟取款200元
            if(temp>=200){
                System.out.println("正在出钞");
                temp -= 200;
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("请取走您的钞票");
            } else{
                System.out.println("账户余额不足");
            }
            // 3. 模拟最新的账户余额
            setBalance(temp);
        }
    }


    public static void main(String[] args) {
        AccountRunnableTest account = new AccountRunnableTest(1000);
        Thread t1 = new Thread(account);
        Thread t2 = new Thread(account);
        t1.start();
        t2.start();

        System.out.println("主线程开始等待");
        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("账户最后的余额为:" + account.getBalance());
    }
}


class Demo{}

10.5、Thread方式实现同步


public class AccountThreadTest extends Thread{
    private int balance;
    private static Demo dm = new Demo();

    public AccountThreadTest() {
    }

    public AccountThreadTest(int balance) {
        this.balance = balance;
    }

    public int getBalance() {
        return balance;
    }

    public void setBalance(int balance) {
        this.balance = balance;
    }

    @Override
    public void run() {
        synchronized (dm) {
            // 1.后台查询账户余额
            int temp = getBalance();
            // 2.模拟取款200元
            if(temp>=200){
                System.out.println("正在出钞");
                temp -= 200;
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("请取走您的钞票");
            } else{
                System.out.println("账户余额不足");
            }
            // 3. 模拟最新的账户余额
            setBalance(temp);
        }
    }


    public static void main(String[] args) {
        AccountThreadTest att1 = new AccountThreadTest(1000);
        att1.start();

        AccountThreadTest att2 = new AccountThreadTest(1000);
        att2.start();

        System.out.println("主线程开始等待");
        try {
            att1.join();
            att2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("账户最后的余额为:" + att1.getBalance());
    }
}

10.6、实现同步方式的方式实现全部方法的锁定


// synchronized 锁定方法
// synchronized (this) 等价于 方法锁定
@Override
    public synchronized void run() {
    	// synchronized (this)  
        synchronized (dm) {
            // 1.后台查询账户余额
            int temp = getBalance();
            // 2.模拟取款200元
            if(temp>=200){
                System.out.println("正在出钞");
                temp -= 200;
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("请取走您的钞票");
            } else{
                System.out.println("账户余额不足");
            }
            // 3. 模拟最新的账户余额
            setBalance(temp);
        }
10.6.1、使用lock锁实现同步

/*
创建锁
private ReentrantLock lock = new ReentrantLock()

lock.lock()
需要锁定的代码
lock.unlock()
*/
10.6.2、wait + notify(线程间的通信)

public class ThreadCommunicateTest implements Runnable{
    private int cnt =1;

    @Override
    public void run() {
        while (true){
            synchronized (this) {
            	notify();
                if(cnt<=100){
                    System.out.println("线程" + Thread.currentThread().getName() + "中 cnt =" + cnt);
                    try {
                        wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    cnt++;
                    // 打完一个进入 wait()
                }else{
                    break;
                }
            }
        }
    }

    public static void main(String[] args) {
        ThreadCommunicateTest tct = new ThreadCommunicateTest();
        Thread t1 = new Thread(tct);
        t1.start();

        Thread t2 = new Thread(tct);
        t2.start();

    }
}
10.6.3、生产者消费者模型
public class StoreHouse {
    private int cnt = 0;  // 记录产品数量

    public synchronized void produceProduct(){
        notify();
        if(cnt<10){
            System.out.println("线程" + Thread.currentThread().getName() + "正在生产第" +(cnt+1) +"个商品");
            cnt++;
        } else{
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public synchronized void consumerProduct() {
        notify();
        if(cnt>0){
            System.out.println("线程" + Thread.currentThread().getName() + "消费第" + cnt +"个商品");
            cnt--;
        }else{
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}
// 生产者线程,实现不断的生产产品
public class ProduceThread extends Thread{

    // 声明一个仓库类型的引用作为成员变量,只为能第哦啊用仓库类中的生产方法,合成复用原则
    private StoreHouse storeHouse;

    // 确保两个线程共用一个仓库
    public ProduceThread(StoreHouse storeHouse){
        this.storeHouse =storeHouse;
    }

    @Override
    public void run() {
        while (true){
            storeHouse.produceProduct();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}
// 生产者线程,实现不断的生产产品
public class ConnsumerThread extends Thread{

    // 声明一个仓库类型的引用作为成员变量,只为能第哦啊用仓库类中的生产方法,合成复用原则
    private StoreHouse storeHouse;

    // 确保两个线程共用一个仓库
    public ConnsumerThread(StoreHouse storeHouse){
        this.storeHouse =storeHouse;
    }

    @Override
    public void run() {
        while (true){
            storeHouse.consumerProduct();
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }
}
public class StoreHouseTest {
    public static void main(String[] args) {
        //创建仓库对象
        StoreHouse storeHouse = new StoreHouse();
        // 创建线程类对象并启动
        ProduceThread t1 = new ProduceThread(storeHouse);
        ConnsumerThread t2 = new ConnsumerThread(storeHouse);
        t1.start();
        t2.start();

    }
}

10.7、有返回值的线程


Callable创建线程

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class ThreadCallableTest implements Callable {
    @Override
    public Object call() throws Exception {
        int sum = 0;
        for(int i=1;i<=10000;i++){
            sum +=i;
        }
        System.out.println("计算的结果为:" + sum);
        return sum;
    }

    public static void main(String[] args) {
        ThreadCallableTest tct = new ThreadCallableTest();
        FutureTask ft = new FutureTask(tct);
        Thread t1 = new Thread(ft);
        t1.start();
        Object ob = null;
        try {
            ob = ft.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        System.out.println("线程的返回结果为:" + ob);
    }
}
class CallableTask implements Callable<Integer>{
	@Override
	public Integer call() throws Exception{
		returen new Randow().nextInt();
		}
}

// 创建线程池
ExcutorService service = Executors.newFixedThreadPool(10);
// 提交任务,并用Future 提交返回结果
Future<Integer> future = service.submit(new CallableTask());

10.8、线程池


  • 本质是通过线程工厂创建线程,默认DefaultThreadFactory, 会给线程池创建线程一些默认值
  • 最终还是通过 new Thread() 创建线程
创建线程池方法声明功能介绍
static ExecutorService newCachedThreadPool()创建一个可根据需要创建新线程的线程池
static ExecutorService newCachedThreadPool(int nThreads)创建一个可重用固定线程数的线程池
static ExecutorService newSingleThreadExecutor()创建一个只有一个线程的线程池
布置任务方法功能介绍
void execute(Runnable command)执行任务和命令,通常用于执行Runnable
Future submit(Callable task)执行任务和命令,通常用于执行Callable
void shutdown()启动有序关闭
// 线程池源码

static class DefaultThreadFactory implements ThreadFactory{

    DefaultThreadFactory(){
        SecurityManager s = System.getSecurityManager();
        group = (s!=null)? s.getThreadGroup() :
                Thread.currentThread().getThreadGroup();
        namePrefix = "pool-" +
                poolNumber.getAndIncrement() +
                "-thread-";
    }

    public Thread newThread(Runnable r) {
        Thread t = new Thread(group, r,
                namePrefix + threadNumber.getAndIncrement(),
                0);

        if (t.isDaemon())
            t.setDaemon(false);
        if (t.getPriority() != Thread.NORM_PRIORITY)
            t.setPriority(Thread.NORM_PRIORITY);
        return t;
    }
}
import demo_three.ThreadCallableTest;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolTest {
    public static void main(String[] args) {
        //1.创建一个线程池
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        //2.向线程池中布置任务
        executorService.submit(new ThreadCallableTest());
        //3.关闭线程
        executorService.shutdown();
    }
}

11、TCP & UDP通信


// 服务端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;

public class ServerStringTest {
    public static void main(String[] args) {
        ServerSocket ss = null;
        Socket s = null;
        BufferedReader br =null;
        //向客户端发送用
        PrintStream ps = null;
        try {
            //1.创建ServerSocket类型的对象并提供端口号
            ss = new ServerSocket(8888);
            // 2.等待客户端连接请求,调用 accept方法
            System.out.println("请等待客户端的连接请求");
            s = ss.accept();
            System.out.println("客户端连接成功");
            // 3.使用输入输入输出流进行通信
            // 实现对客户端发来内容的接收并打印
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String s1 = br.readLine();
            System.out.println("客户端发送来的内容为:" + s1);
            ps = new PrintStream(s.getOutputStream());
            ps.println("消息收到了");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 4.关闭Socket并释放有关资源
            if(null != br){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != s){
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != ss){
                try {
                    ss.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(null != ps){
                try {
                    ps.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
//客户端
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Scanner;

public class Client {
    public static void main(String[] args) {
        Socket s = null;
        PrintStream ps = null;
        Scanner sc = null;
        BufferedReader br =null;

        try {
            //1.创建Socket类型的对象,并提供服务器的主机名和端口号
            s = new Socket("127.0.0.1",8888);
            System.out.println("连接服务器成功");
            //2.使用输入输出流进行通信
            // 实现客户端向服务器发送字符串内容 “hello”
            ps = new PrintStream(s.getOutputStream());
            System.out.println("请出入要向服务器发送的内容");
            sc = new Scanner(System.in);
            String str1 = sc.next();
            ps.println(str1);
            //ps.println("hello");
            System.out.println("客户端内容发送成功");
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            String s1 = br.readLine();
            System.out.println("服务器发送来的内容为:" + s1);

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //3.关闭Socket并释放有关资源
            if(null != s){
                try {
                    s.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(null != ps){
                try {
                    ps.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(null != br){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值