java学习笔记
JAVA学习
第一章 基础常识
1.1基础常识
1.软件开发
软件:计算机数据和指令的集合,系统软件和应用软件。
2.人机交互方式
图形化界面(一般)。
命令行方式:控制台输入指令。
3.常用DOS命令
 dir:列出当前文件及文件夹
 md:创建目录
 rd: 删除目录
 cd:进入指定目录
 cd..:退回上级目录
 cd\:退回根目录
 del:删除文件
 exit:推出dos命令
1.2 java语言概述
1.计算机语言
 人与计算机交流方式:java、c、c++
2.面向对象
 能够更好的在抽象层面来分析问题。
3.java解释型语言
 java程序编译为字节码格式,在任何系统的解释器中运行。
1.3 java语言运行机制及以运行过程
1. java特点
 (1)面向对象
 (2)健壮性、完善性
 (3)跨平台性:一次编写,处处运行。只需要安装java虚拟机 (JVM),由JVM负责java程序在该系统中的运行。
2.java两种核心机制
 (1)java虚拟机(Java Virtal Machine):JVM
 (2)垃圾收集机制(Garbage Collection):GC
3.跨平台性(因为JVM)

4.核心机制——java虚拟机
 (1)JVA是一个虚拟的计算机,具有指令集并使用不同的存储区域。负 责执行指令,管理数据、内存、寄存器。
 (2)java虚拟机机制屏蔽了底层运行平台的差别。

5.核心机制——垃圾回收
 (1)c、c++:程序员手动编代码回收,(有点:能够在内存不使用时快 速回收,准确高效;缺点:容易失误出现bug)
 (2)java: 垃圾回收是自动的,开了一个线程自动检测不用的内 存去回收(有点:自动的不会忘掉;缺点:回收不及时)
1.4 jdk、jre、jvm的关系
1. 什么是jdk、jre
 (1)jdk:Java开发工具包,包括jre;其中的开发工具:编译工具 (javac.exe)打包工具(jar.exe)等
 (2)jre:java运行环境,包括java虚拟机(JVM),和Java程序所需的 核心类库等,如果想要运行一个开发好的Java程序,计算机中只 要安装JRE即可。
 简而言之:jdk开发,jre运行。
2 jdk、jre、jvm的关系
 JDK( JRE (JVM) )
1.5开发体验——HelloWorld
public class Test{
        public static void main(String[] args){
               System.out.print("hello world");
        }	
}
 DOS命令运行:
 编译:javac Test.java
 运行:java Test
1.6 注释
1.特性:
 提高代码阅读性,调试程序的重要方法
2.注释类型
 单行://
 多行:/* */
 文档注释(Java特有):
/**
*文档注释
*这是一个打印Hello World的类
*@author ahd
*version
*/
第二章 java基本语法
2.1关键字
1.关键字
 定义:被Java赋予特殊含义,用作专门用途的字符串(单词)
 特点:都是小写

2.保留字
 现在还没使用,以后的版本可能会使用为关键字:byValue、cast、 future、generic、inner、operator、outer、rest、var、goto、const;
2.2 标识符
1. 标识符
 可以自己取名的地方都叫标识符。
2.规范
 (1)26个英文字母,0-9,_或$组成;
 (2)数字不可以开头;
 (3)不可以单独使用关键字和保留字,可以包含;
 (4)严格区分大小写
 (5)不包含空格
 (6)尽量有意义
2.3 java中的名称命名规范
1.Java中的命名规范
 (1)包名:多单词组成时所有都小写;
 (2)类名、接口:多单词组成时,所有首字母都大写;
 (3)变量名、方法名:第一个单词首字母小写,第二个往后 首字 母大写:xxxYyyZzz;
 (4)常量名:所有都大写,多单词用下划线链接 XXX_YYY_ZZZ
2.4 变量概念(和C一样)
1.变量格式
 数据类型 变量名 = 变量的值
2.变量的概念
 (1)内存中的一个储存区域;
 (2)必须先声明后使用;
 (3)变量是通过变量名来访问的。
2.5 变量的分类

1. long 类型
 long L = 3l 要在后面跟上 l (字母)
2. float类型
 floa f = 1.22f 跟上字母 f
2.6 运算符
1.算数运算符
 对负数取模,可以忽略负号,被模数是负数不可忽略。
2.逻辑运算符
 (1)^ 异或:两个里面一个成立一个不成立;
 (2)“&”和“&&“区别:单个时,左边无论真假,右边都参与运算;双数 时,左为真时,右参与,否则不参与;
 ”|“和“||” :单个同理;双数时左边为真,右边不参与运算。
3. 位运算符

 (1)位运算符是直接对二进制进行运算。
 (2)左移:m<<n = m*2的n次方
 3<<2 = 3 * 2 * 2 = 12
 右移:乘以2的-n次方
 (3)无符号右移:
 正数:与右移一致
 负数:看图

	(4)与或运算![与或运算]

 (5)异或运算

 (6)反码

4. 三目运算符
 (1)格式:

int i = 0;
int k = i > 0 ? 1 : 0;
5.运算符的优先级

2.7程序流程控制
1. 顺序结构
2.分支结构
3.循环结构
2.8数组
1.一维数组
int[] ii;
int a[];
//动态初始化:数组声明且为其分配空间,与复制操作分开进行;
int[] b = new int[4];
    b[0] = 1;
	b[1] = 2;
	b[2] = 3;
//静态初始化:
int[] c = new int[]{1,2,3,4};
2.二维数组
int[] ii0 = new int[2][3];
第三章 面向对象编程
3.1面向对象与面向过程
1.面向对象三大特征
 封装、继承、多态
2.类class
 (1)属性:对应类中的成员变量
 (2)行为:对应类中的成员方法
3.思想概述
 (1)类=汽车设计图;对象=实实在在的汽车
 (2)对象=实实在在的汽车
 (3)面向对象程序设计的重点时类的设计
 (4)定义类其实就是定义类中的成员(成员变量(零部件)和方法(运 行))
3.2类
 类成员:属性、方法、构造器、代码块、内部类。
1.类的写法
public class Animal {
    String name;//动物名称
    int eyes;
    int legs;
    public int getEyes(){
        return eyes;
    }
    public void eat(String food){
        System.out.println("动物吃的是:"+food);
    }
    public void move(String moveType){
        System.out.println("此种动物的移动方式是:"+moveType);
    }
}
2.类的实例化
public class Test {
    public static void main(String[] args){
        //实例化动物类
        Animal animal = new Animal();
        animal.name = "小狗";
        animal.eyes = 2;
        animal.legs = 4;
        System.out.println("动物是"+animal.name);
        animal.eat("骨头");
        animal.move("爬");
        int a = animal.getEyes();
        System.out.println(a);
    }
}
3.类的属性
	(1)private//私有变量,只能在在自己的类里面使用。
			  public//公有变量。
 (2)成员变量:
 类变量:以static修饰,静态;
 实例变量:在类实例化位对象之后才能使用。
 (3)局部变量:
 形参、方法局部变量、代码块局部变量。
4.类的方法
public class Student {
    public String name;
    public  int age;
    public String course;
    public String interest;
    /**
     显示学生个人信息
     */
    public void showIofo(){
        System.out.println("姓名:"+name);
        System.out.println("年龄:"+age);
        System.out.println("课程:"+course);
        System.out.println("兴趣:"+interest);
    }
}
5.匿名对象
 不定义对象的句柄,直接调用这个对象的方法
new Person().shout();
 使用场景:只调用一次就不再调用了。
 经常将匿名对象作为实参传递给一个方法使用。
6.面向对象思想“落地”法则(1)
 (1)关于类的设计,即设计类的成员:属性和放法;
 (2)类的实例化,即创建类的对象;
 (3)通过“对象.属性”、“对象.方法” 执行。
7.方法的重载
//多个相同名称方法在一个类中共存,参数肯定不一样
public int add(int x,int y){
    return x+y;
}
public double add(int x,double y){
    return x+y;
}
public int add(int x,int y,int z){
    return x+y+z;
}
8.方法的参数传递
 (1)java里方法的参数传递方式只有一种:值传递。即将实际参数值的副 本传入方法内
 (2)JVM的内存模型

(3)方法的参数传递
 a.如果方法的形参是基本数据类型,那么实参(实际的数据)向形参传递 参数时,就是直接传递值,把实参的值复制给形参。
 b.如果方法的形参是对象,那么实参(实际的对象),向形参传递参数 时,也是把值给形参,这个值是实参在栈内存中的值,也就是引用对象 在堆 内存中的地址。
 基本数据类型都是保存在栈内存中,引用对象在栈内存中保存的是引用 对象的地址,那么方法的参数传递是传递值(是变量在栈内存的值)。
3.3面向对象特征之一:封装和隐藏
 先把属性设置位私有的(private),通过set和get方法来设置获取属性。
3.4四种访问权限修饰符

 在一个java文件中可以写多个class,但是只有一个public,其他的只能缺省。
3.5类的成员之三:构造器(构造方法)
1.构造器特征
 (1)语法格式:
 修饰符 类名(参数列表){
 初始化语句;
 }
public Animal(){legs = 4;}
 (2)new对象实际上就是调用类的构造方法。
2.构造器的重载
 (1)构造器也叫构造方法
public class Person(){
    public Person(int a){}
    public Person(String n){}
    public Person(){int a,String n}
}
 (2)重载意义:为了方便灵活的创建出不同需求的对象,相当于提供了多个初始化new对象的模板。
3.6关键字——this
public class Person(){
    
    public Person(){
        
    }
    
      public Person(int age){
        this.age = age;
    }
    
    public Person(int age,String name){
        this.age = age;
        this.name = name;
    }
	int age;
    String name;
    
    public void setName(String name){
        this.name = name;
    }
    
     public void setName(String name){
        this.setName(name);
    }
}
3.7 JavaBean
 (1)JavaBean是一种Java语言写成的可重用组件;
(2)所谓javaBean,是指符合如下标准的Java类:
 a.类是公共的;
 b.有一个无参的公共构造器;
 c.有属性,属性一般是私有的,且有对应的get、set方法。
(3)用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用Java代码创造的对象打包,其他开发者可以用其他的程序或者应用来使用些对象。用户可以认为javabean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
第四章 高级类特性1
4.1 面向对象特征之二——继承
1.继承
 (1)把共性的东西抽取出来形成父类,实际需求的子类在继承父类的基础 上写自己特有的代码即可。
 (2)继承的出现提高代码复用性;
 让类与类之间产生了关系,提供了多态的前提;
 不要仅为了获取其他类中某个功能而去继承(逻辑关系)。
 (3)子类不是父类的子集,是扩展。
 (4)子类不能直接访问父类中的私有变量,可以用get set方法;
 (5)Java类只能单继承(一个子类只能继承一个父类)。
public class Person{
    String name;
    int age;
    int sex;
    
    public void info(){
        System.out.println(this.name);
        System.out.println(this.age);
        System.out.println(this.sex);
    }
}
public class Student extends Person{
    String school;
    
    public void info(){
        System.out.println(this.name);
        System.out.println(this.age);
        System.out.println(this.sex);
        System.out.println(this.school);
    }
}
2.方法的重写(区别重载)
 (1)子类重写父类的方法只是重写方法体的代码,名称参数不变;
 (2)如果父类是public的,子类就不能使用缺省以下的;
 (3)重写和非重写的方法必须同时是static或同时是非static的;
 (4)子类方法抛出的异常不能大于父类被重写方法的异常。
4.2 关键字——super
1.概念
 (1)使用super,子类可以调用子类之上的所有父类层级。
public class Person{
    String name;
    int age;
    int sex;
    
    public void info(){
        System.out.println(this.name);
        System.out.println(this.age);
        System.out.println(this.sex);
    }
}
public class Student extends Person{
    String school;
    
    public void info(){
        System.out.println(this.name);
        System.out.println(this.age);
        System.out.println(this.sex);
        System.out.println(this.school);
    }
}
public class test extends Student{
	super.name = "ahd"; //调用父类的父类
    super.school = "shenhang"; //调用父类;
}
2.this和super的区别

4.3简单类对象的实例化过程

4.4面向对象特征之三——多态
1.体现概念
 (1)方法的重载(overload)和方法的重写(overwrite);
 (2)对象的多态性——可以直接应用在抽象类和接口上。
2.引用变量的两个类型
 (1)编译时类型和运行时类型:编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给改变量的对象决定;
 (2)若编译时类型和运行时类型不一致,就出现多态。
3.多态小结
(1)前提:
 a. 需要存在继承或者实现关系;
 b. 需要有覆盖操作。
(2)成员方法:
 a. 编译时:要查看引用变量所属的类中是否有所调用的方法;
 b. 运行时:调用实际对象所属的类中的重写方法。
(3)成员变量:
 不具备多态性,只看引用变量所属的类。
4.5 Object类
1. 概念
 (1)Objec类是所有Java类的根父类(基类)。
 (2)如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类。
2. 主要方法

3. toString方法
 (1)父类Object的toString方法就是输出当前对象的内存地址,如果想要输出类的其他信息,重写toString方法。
4.6 对象类型转换
1.概念
 (1)对Java对象的强制类型转换成为造型;
 (2)从子类到父类的类型转换可以自动进行;
 (3)从父类到子类的类型转换必须通过造型(强制类型转换)实现;
 (4)无继承关系的引用类型间的转换时非法的。
public class Test{
    public static void main(String[] args){
        
        //Person是Student的父类,从子类到父类的类型转换是自动的
        Student s = new Student();
        Person p = s; 
        
        //从父类到子类的类型转换必须强制
        Person p = new Person();
        Student s = (Student) p;
    }
}
2.对比基础数据类型

4.7 ==操作符与equal方法
1.==概念
 (1)== :两个变量相等,即位true;
 (2)用“==”进行比较时,符号两边必须兼容(可以自动转换的基本数据类型除外);
 (3)用==比较引用类型时,必须指向同一个对象,才返回true。
2. String对象的创建

4.8包装类
1.概念
 (1)针对八种基本定义相应的引用类型——包装类(封装类);
 (2)有了类的特点,就可以调用类中的方法。

2.基本类型与字符串相互转换
 (1)基本类型转字符串
int i = Integer.parseInt("123");
float f = Float.parseFloat("0.41");
boolean b = Boolean.parseBoolean("false");
 (2)字符串转基本类型
String istr = String.valueOf(i);
String fstr = String.valueOf(f);
String bstr = String.valueOf(true);
3.作用
 主要应用字符串与字符串相互转化。
第五章 高级类特性2
5.1 关键字static
1.概念
 (1)静态 ,类变量,不用实例化直接通过 类名 . 属性名 可以使用,是类的一部分,被所有这个类的实例化对象所共享。也可以叫做静态变量。
 (2)同样类属性、类方法也可以使用。
2.设计思想
(1)有些类属性和方法不想因为对象不同而频繁通过new对象方式去调用,就写static。
 (2)类方法,也就是静态方法在工具类中使用的频繁。
/**
*工具类
*判断是否为一个空字符串
*/
public class Utils{
    public static boolean isEmpty(String s){
        bollean flag = false;
        if (s != null && !s.equal("")){
            falg = true;
        }
        return flag;
    }
}
3.特点
(1)类加载之后,静态方法或者属性就能用了,类名 . **;
 (2)类变量,这种可以被所有的实例化对象共享的属性,使用要慎重,只要修改,所有的都要变动。
5.2 单例设计模式
1. 设计模式
 设计模式就是在我们实际编程的过程中,逐渐总结出的一些解决问题的套路。
2.单例
 (1)只有一个实例(实例化对象);
 (2)在整个软件系统的运行过程中,这个类只被实例化一次,以后不管在哪都只调用这一个实例。
 (3)例如实例化对象的创建要消耗大量的时间和资源。
 (4)使用单例模式解决什么问题?一般都是new对象太费劲,或者频繁的new新的对象没有必要。
3.单例模式——饿汉式
 类加载之后,还没有人调用的时候,就先new好一个对象,以后不论谁来调用getInstance方法,都是直接返回之前new好的对象。
/**
*饿汉式
*/
public class Single{
    //构造方法私有化,调用这个类的人就不能直接使用new来创建对象
    private Single(){
        
    }
    //私有的Single类型的类变量
    private static Single single = new Single();
    public static Single getInstance(){
        return single; 
    }
}
4.单例模式——懒汉式
 最开始对象是null,知道有第一个人调用,才new一个对象,之后所有调用都用这个对象。
/**
*懒汉式
*/
public class Single1{
    //构造方法私有化,调用这个类的人就不能直接使用new来创建对象
    private Single1(){
        
    }
    //私有的Single类型的类变量
    private static Single s1 = null;
    public static Single getInstance(){
        if(s1 == null){
            s1 = new Single1();
        }
        return s1;
    }
}
5.3类的成员之四:初始化块(代码块)
1.非静态代码块(没有static修饰)
 (1)可以有输出语句;
 (2)可与对类的属性声明进行初始化操作;
 (3)可以调用静态和非静态的变量或方法;
 (4)若有多个非静态代码块,从上到下依次执行;
 (5)每次创建对象的时候,都会执行一次,且先于构造器执行。
2.静态代码块(用static修饰)
 (1)可以有输出语句;
 (2)可与对类的属性声明进行初始化操作;
 (3)不可以调用非静态的属性和方法;
 (4)若有多个静态代码块,从上到下依次执行;
 (5)静态代码块的执行要先于非静态代码块;
 (6)静态代码块只执行一次。
3.作用
 匿名内部类没有构造方法,只能用代码块代替构造方法初始化。
5.4关键字:final(最终)
1.特性:
 (1)final标记的类不能被继承;
 (2)final标记的方法不能被子类重写;
 (3)final标记的变量(成员变量或局部变量)即称为常量,名称大写,且只能赋值一次;
 (4)final和static同时修饰成为全局变量。
2.总结
 final表示最终,可以修饰变量、方法、类。
5.5抽象类(abstract class)
1.抽象化处理
 就是不写具体的实现。
2.abstract(抽象)
 (1)用abstract修饰一个类叫抽象类
 (2)用abstract修饰一个方法叫做抽象方法。
 抽象方法只有声明,没有方法的实现,以分号结束
abstract int abstractMethod(int a );
 (3)含有抽象方法的类必须声明为抽象类;
 (4)抽象类不能被实例化。抽象类是用来被继承的,抽象类的子类必须重写父类的抽象方法。若没有全部重写,则还是为抽象类。
 (5)不能用abstract修饰属性、私有方法、构造器、静态方法、final的方法。
3.抽象类应用
 抽象类是用来模型化那些父类无法确定全部实现,由子类提供具体实现的对象的类。
4.模板方法设计模式
 抽象类就是多个子类的通用模板,抽象类就像一个大纲,里面的每个抽象方法每个章节的标题,子类去根据这些标题写出每个章节。
5.6接口
1.定义
 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是java中不支持多继承,有了接口就可以得到多继承的效果。
2.特点
 (1)接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
 (2)一个类可以实现多个接口,接口也可以继承其他接口。
 (3)接口中所有成员变量都默认是有 public static final 修饰的。
 (4)所有的方法都是由 public abstract 修饰。
 (5)裂口没有构造器。
 (6)接口可以继承,接口采用多层继承制。
 (7)如果一个类即继承父类又实现接口,先继承、后实现。
public class TestinImpl2 extends Person implements TestIn,TestIn1{
      @Overdide
    public void Test(){
        
    }
      @Overdide
    public void Test1(){
        
    }
}
3.实现
public interface TestIn{
    int ID = 1;
    void test();//public abstraact void test();
}
public interface TestIn1{
    void test1();//public abstraact void test1();
}
/**
*子类继承父类,只能继承一个父类
*类可以实现多个接口,多个接口用 ,分隔
*/
public class TestInImpl implements TestIn,TestIn1{
    @Overdide
    public void Test(){
        
    }
      @Overdide
    public void Test1(){
        
    }
}
4.接口中存在的问题

5.总结
 抽象类是对于一类事物的高度抽象,其中既有属性也有方法,接口是对方法的抽象,也就是对一系列动作的抽象。
 当需要对一类事物抽象的时候,应该是使用抽象类,好形成一个父类,
 当需要对一系列的动作抽象时,就使用接口,需要使用这些动作的类就去实现相应的接口。
6.工厂方法(FactoryMethod)
 通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略。类中new一个对象很容易,但是时机很关键,工厂模式就是解决的这个问题。
5.7类成员之五:内部类(Inner class)
1.创建
public class Test{
	int i;
    public int z;
    class A{
        int i;
        public void setTestFiled(){
            Test.this.i = 1;
            Test.this.z = 2;
        }   
        public void set(){
            this.i = 10;
        } 
    }
    
    public void setInfo(){
        new A().setTestFiled();//外部类要使用自己的内部类的方法,要先new内部类的对象。
    }
    
    public void showInfo(){
        System.out.println(this.i);
        System.out.println(this.z);
    }
    
}
2.特性
 (1)可以声明为fianl的;
 (2)和外部类不同,内部类可以声明为private或protected;
 (3)内部类可以声明为static的,但此时就不能再使用外层类的非static的成员变量。
 (4)可以声明为abstract,可以被继承;
 (5)非static的内部类中的成员不能声明为static,只有在外部类或者static的内部类才可以声明static成员。
3.作用
内部类主要是解决java不能多重继承的问题
/**
*A要同时继承B和C
*/
class A{
    
    public void testB(){
        new InnerB().testb;
    }
    
     public void testB(){
        new InnerB().testb;
    }
    
    private class InnerB extends B{
        @override
        public void testb(){
            System.out.println("这是重写之后的testB方法");
        }
    }
    
    private class InnerC extends C{
        @override
        public void testC(){
            System.out.println("这是重写之后的testC方法");
        }
    }
}
class B{
    public void testb(){
        
    }
}
class C{
    public void testc(){
        
    }
}
第六章 异常处理
6.1 java异常
1.种类
 (1)Error:JVM系统内部错误,资源耗尽等严重情况。
 (2)Exception:其他因编程错误或偶然的往外在因素导致的一般性问题。
2.异常处理机制(抓抛机制)
 (1)捕获异常
int i = 0;
try{//用try{}来括住一段有可能异常的代码段
    System.out.println(3/i);
}catch(Exception e){//当不知道捕获的是什么类型的异常时,可以直接使用所有异常的父类Exception
    System.out.println(e.getmessage());
}
 (2)抛出异常
public class Test1 {
    public static void main(String[] args){
        B b = new B();
        try {
            b.test();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
class B{
    int i;
    public void test() throws Exception{//可以使用throws在代码这抛出异常,在调用方法去捕获异常
        B b = null;
        System.out.println(b.i);
    }
}
【注意】
 子类重写父类的方法时,抛出的异常范围不能大于父类。
第七章 集合
7.1 java集合概述
1.概述
 java集合类存放在java.util包中,是一个用来存放对象的容器。
 (1)集合只能存放对象
 (2)集合存放的是多个对象的引用,对象本上还是存放在堆中。
 (3)集合可以放不同类型、不限数量的数据类型。
2.体系
 java集合分为Set、List、Map 三大体系,
 (1)Set:无序、不可重复的集合
 (2)list:有序、可重复的集合
 (3)Map:具有映射关系的集合
3.HashSet集合
 (1)HashSet按照Hash算法来存储集合中的元素,因此具有很好的存取和查找功能。
 (2)特点:
 · 不能保证元素的排列顺序
 · 不可重复
 · HashSet不是线程安全的
 · 集合元素可以是 null
 (3)HashSet集合是根据对象的hashCode值决定该对象在HashSet中的存储位置。
【注】hashCode就是对象在hash表中的位置
 (4)增删改
import java.util.HashSet;
import java.util.Set;
public class HashTest {
    public static void main(String[] args){
        Set set = new HashSet();
        set.add(1);//增加元素
        set.add("a");
        System.out.println(set);
        set.remove(1);移除元素
        System.out.println(set);
       System.out.println( set.contains("a"));
       set.clear();//清空集合
        System.out.println(set);
        
        System.out.println(set.size());//获取元素的个数
    }
}
 (5)遍历
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class HashTest {
    public static void main(String[] args){
        Set set = new HashSet();
        set.add("a");
        set.add("b");
        set.add("c");
        set.add("d");
        System.out.println(set);
        //使用迭代器遍历集合
        Iterator it = set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        //for each迭代集合
        for(Object obj : set){//把set的每一个值取出来赋值给obj直到循环set的所有值
            System.out.println(obj);
        }
    }
}
 (6)泛型
 Set<String> set = new HashSet<String>();//比如指定String类型,那么这个集合就不能存其他类型了
4.TreeSet集合
 (1)TreeSet是SortSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
 (2)TreeSet的两种排序方式:自然排序和定制排序,默认为自然排序。
 (3)自然排序:TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素之间的大小关系,然后将集合元素按升序排列
 · 如果this(当前元素)>obj(之后元素),返回1
 · 如果this > obj,返回-1
 · 如果this > obj,返回0,认为相等
 【注】必须放入同样的对象,可以用泛型来限制。
 (4)定制排序(实现Comparator接口中的Compare方法)
import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class TreeSetTest {
    public static void main(String[] args){
        Person p1 = new Person("张三",23);
        Person p2 = new Person("李四",20);
        Person p3 = new Person("王五",16);
        Person p4 = new Person("Lusy",29);
        Set<Person> set = new TreeSet<Person>(new Person());
        set.add(p1);
        set.add(p2);
        set.add(p3);
        set.add(p4);
        for(Person p : set){
            System.out.println(p.name+" "+p.age);
        }
    }
}
class Person implements Comparator<Person>{//把person存到TreeSet中,按照年龄排序
    int age;
    String name;
    public Person(){}
    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }
    @Override
    public int compare(Person o1, Person o2) {
        if(o1.age>o2.age){
            return 1;
        }else if(o1.age<o2.age){
            return -1;
        }else {
            return 0;
        }
    }
}
5.List集合
 List是接口,实现类是ArrayList。
 (1)特点:
 · 允许使用重复元素,可以通过索引来访问指定位置的集合元素
 · List默认按元素的添加顺序设置元素的索引
 · List集合里添加了一些根据索引来操作集合元素的方法
 (2)操作元素的方法
import java.util.ArrayList;
import java.util.List;
public class ListTest {
    public static void main(String[] args){
        List<String> list = new ArrayList<String>();
        list.add("b");
        list.add("d");
        list.add("c");
        list.add("a");
        list.add("b");
        System.out.println(list);
        System.out.println(list.get(2));//通过所以呢来访问元素
        list.add(1,"e");//在指定索引位置插入数据,其他后移
        System.out.println(list);
        List<String> l = new ArrayList<String>();
        l.add("123");
        l.add("456");
        list.addAll(2,l);//在指定位置插入集合
        System.out.println(list);
        System.out.println(list.indexOf("a"));//获取指定元素在集合中第一次出现的下标
        System.out.println(list.lastIndexOf("b"));//获取指定元素在集合中最后一次出现的下标
        list.remove(1);//移除指定下标的元素
        System.out.println(list);
        
         list.set(0,"bb");//修改指定位置的元素
        System.out.println(list);
        List<String>sublist = list.subList(2,4);//截取集合元素,左包含右不包含
        System.out.println(sublist);
    }
}
5.Map集合
 (1)定义:Map用于保存有映射关系的数据,Map有两组值(Key,Value),都可以是引用数据,同一个Map对象里面的key不允许重复,Key和Value之间存在单向的一对一关系。
 (2)Map接口和HashMap
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class MapTest {
    public static void main(String[] args){
        Map<String,Integer> map = new HashMap<String, Integer>();
        map.put("b",1);//添加数据
        map.put("c",2);
        map.put("e",2);
        System.out.println(map);
        System.out.println(map.get("c"));//根据Key取值
        map.remove("c");//根据Key移除键值对
        System.out.println(map);
        System.out.println(map.containsKey("b"));//判断当前集合是否包含指定key
        System.out.println(map.containsValue(2));//判断是否有指定的value
        Set<String>keys = map.keySet();//获取map集合中所有的key
        map.values();//获取map集合中所有的value
        //遍历map集合通过map.keySet();
        for(String key : keys){
            System.out.println("key:"+key+"value:"+map.get(key));
        }
        //通过map.entrySet();
        Set<Map.Entry<String,Integer>> entry = map.entrySet();
        for(Map.Entry<String,Integer> en : entry){
            System.out.println("key:"+en.getKey()+"value:"+en.getValue());
        }
    }
}
 (3)Hash和Hashtable
 区别:Hashtable是线程安全的Map实现,但HashMap是线程不安全的;
 Hashtable不允许使用null作为key和value的,而HashMap可以。
 (4)TreeMap:与TreeSet相似。
7.2操作集合的工具类
1.Collections定义
 Collections是一个操作Set、List和Map等集合的工具类。
2.方法
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class Test01 {
    public static void main(String[] args){
        List<String> list = new ArrayList<String>();
        list.add("b");
        list.add("cd");
        list.add("ca");
        list.add("a");
        list.add("1");
        System.out.println(list);
        Collections.reverse(list);//反转list
        System.out.println(list);
        Collections.shuffle(list);//随机排序
        System.out.println(list);
        Collections.sort(list);//list字典升序排序
        System.out.println(list);
        Collections.swap(list,0,4);//交换两个元素
        System.out.println(list);
        System.out.println(Collections.max(list));//输出最大
        System.out.println(Collections.min(list));//输出最小
        System.out.println(Collections.frequency(list,"a"));//指定元素出现的次数
        Collections.replaceAll(list,"a","aa");//新的值代替旧值
        Student s1 = new Student(14,"张三");
        Student s2 = new Student(13,"李四");
        Student s3 = new Student(12,"王五");
        Student s4 = new Student(11,"小六");
        List<Student> stus = new ArrayList<Student>();
        stus.add(s1);
        stus.add(s2);
        stus.add(s3);
        stus.add(s4);
        System.out.println("------------------");
        Collections.sort(stus,new Student());
        for(Student stu : stus){
            System.out.println(stu.name+","+stu.age);
        }
    }
}
class Student implements Comparator<Student>{
    int age;
    String name;
    public Student(){
    }
    public Student(int age,String name){
        this.age = age;
        this.name = name;
    }
    @Override
    public int compare(Student o1, Student o2) {//根据年龄升序排列
       if(o1.age>o2.age){
           return 1;
       }else if(o1.age<o2.age){
           return -1;
       }else {
           return 0;
       }
    }
}
第八章 泛型
8.1泛型的使用
1.泛型类
public class testfanxing {
    public static void main(String[] args){
        A<String> a1 = new A<String>();//在new A的对象指定泛型的类型string
        a1.setKey("xxx");//对象使用setKey(T key)方法时参数类型就是String
        String s = a1.getKey();//返回值,就由new对象确定返回值是string
    }
}
/**
 * 此次的泛型T可以任意取名
 * 一般使用大写的T,意为type
 * */
class A<T>{
    private T key;
    public void setKey(T key){
        this.key = key;
    }
    public T getKey(){
        return this.key;
    }
}
2.泛型接口
 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需要将泛型的声明也一起加到类中
public class testinterface {
    public static void main(String[] args){
        B1<Object> b1 = new B1<Object>();//必须指定泛型
        B2 b2 = new B2();//不用指定泛型
    }
}
interface IB<T>{
    T test(T t);
}
class B1<T> implements IB<T>{
    @Override
    public T test(T t) {
        return null;
    }
}
/**
 * 如果实现接口时指定接口的泛型的具体数据类型
 * 这个实现接口所有的位置都要泛型替换实际的具体数据类型
 * */
class B2 implements IB<String>{
    @Override
    public String test(String s) {
        return null;
    }
}
3.泛型方法
 方法也可以被泛型化,不管此时定义在其中的类是不是泛型化的。在反省方法中可以定义泛型参数,此时,参数的类型就是传入数据的类型。
class Cc<E>{
    private E e;
    public static <T> void test3(T t){
        //在静态方法上不能使用类定义的泛型,如果要使用,只能静态方法自己定义泛型
    }
    
    public <T> void test(T s){//无返回值的泛型方法
        System.out.println(this.e);//在类上定义的泛型,可以在普通方法上使用
        T t = s;
    }
    public <T> T test1(T s){//有返回值的泛型方法
        return s;
    }
    public <T> void test2(T... strs){//形参为可变参数的泛型方法
        for(T s : strs){
            System.out.println(s);
        }
    }
}
4.通配符
/**
*不确定集合中的元素具体的数据类型
*使用?表示所有类型
*@param list
*/
第八章 枚举和注解
8.1枚举类
1.使用enum定义枚举类
public class Testmeiju {
    public static void main(String[] args){
        //Season.SPRING,这段执行就是获取一个Season的对象
        Season spring = Season.SPRING;
        spring.showInfo();
        Season spring1 = Season.SPRING;
        //每次执行Season.SPRING获得是相同的对象,枚举类中的每个枚举都是单例模式的
        System.out.println(spring.equals(spring1));
    }
}
enum Season{
    SPRING("春天","还好"),//此处相当于调用有参数的私有造方法
    SUMMER("夏天","热热"),
    AUTUMN("秋天","爽爽"),
    WINTER("冬天","冷冷");
    private final String name;
    private final String desc;
    Season(String name,String desc) {
        this.name = name;
        this.desc = desc;
    }
    public void showInfo(){
        System.out.println(this.name+":"+this.desc);
    }
}
2.枚举类实现接口
与普通接口的实现相同
8.2注解(Annotation)
1.定义
 代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理。
第九章 IO流
9.1 java.io.File类的使用
1.IO原理及流的分类
 (1)文件流
 数据流的读写都是基于文件的操作。
 (2)缓冲流
 数据流的读写都是基于内存的操作。
9.2 File类
1.作用
 file只能操作文件,不能操作文件内容。
2.方法
import java.io.File;
public class testFile {
    public static void main(String[] args){
        File f = new File("F:\\java学习\\testfile\\tt.txt");//这个对象f就是tt.txt文件
        //获取文件名
        System.out.println(f.getName());
        //获得路径
        System.out.println(f.getPath());
        //获得绝对路径
        System.out.println(f.getAbsolutePath());
        //返回一个用当前文件的绝对路径构建的file对象
        System.out.println(f.getAbsoluteFile());
        //返回当前文件或者文件夹的父级路径
        System.out.println(f.getParent());
        //重命名
        f.renameTo(new File("F:\\java学习\\testfile\\tt1.txt"));
        //判断是否存在
        File f1 = new File("F:\\java学习\\testfile");
        System.out.println(f1.exists());
        //是否可读写
        File f2 = new File("F:\\java学习\\testfile\\tt1.txt");
        System.out.println(f2.canRead());
        System.out.println(f2.canWrite());
        //判断当前的file的对象是否为文件
        System.out.println(f2.isFile());
        //判断是否为文件夹
        System.out.println(f2.isDirectory());
        //获取最后修改时间
        System.out.println(f2.lastModified());
        //返回文件长度,单位是字节数
        System.out.println(f2.length());
        File f3 = new File("F:\\java学习\\testfile\\tt2.txt");
        //创建文件
        if(!f3.exists()){
            try {
                f3.createNewFile();
            }catch(IOException e){
                e.printStackTrace();
            }
        }
        //删除文件
        f3.delete();
        //创建单机目录
        File f4 = new File("F:\\java学习\\testfile\\cc");
        f4.mkdir();
        //创建多层目录
        File f5 = new File("F:\\java学习\\testfile\\a\\b\\c");
        f5.mkdirs();
        File f6 = new File("F:\\java学习\\testfile");
        String[] f11 = f6.list();//返回文件夹的子集
        for(String s : f11){
            System.out.println(s);
        }
    }
}
9.3 Java IO原理
1.输入input
 读取外部数据到程序(内存)中。
2.输出output
 将程序(内存)数据输出到磁盘、光盘等储存设备中。
3.流的分类
 (1)数据单位不同:字节流(8 bit),字符流(16 bit)。
 (2)流向不同:输入流,输出流。
 (3)角色不同:节点流,处理六。

4.文件字节流
(1)文件字节输入流
import java.io.FileInputStream;
    public static void testFileIutputStream(){
        try {
            FileInputStream in =new  FileInputStream("F:/java学习/testfile/tt1.txt");
            byte[] b = new byte[20];//设置一个byte数组来接收读取的文件内容
            int len = 1;//设置一个读取数据的长度
            //in.read(b) 方法的返回值是返回读取的数据长度,当返回的是-1时,表示读完。
            while((len = in.read(b)) != -1){
                //string(b,0,len)参数1是缓冲数据的数组,参数2是从数组的哪个位置开始转化字符串,参数3是总共转化了几个
                System.out.println(new String(b,0,len));
            }
            in.close();//注意,流在使用完毕之后一定要关闭
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
(2)文件字节的输出流
public static void testFileOutputStream(){
        try {
            //指定x向tt4中输出
            FileOutputStream out =new FileOutputStream("F:/java学习/testfile/tt4.txt");
            String str = "dffsffds";
            //把数据写到内存
            out.write(str.getBytes());
            //把内存中的数据刷写到硬盘
            out.flush();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
(3)复制文件到指定文件夹
/**
     * 复制文件到指定位置
     * @param inPath 源文件的路径
     * @param outPath 复制到的文件夹的位置
     */
    public static void copyFile(String inPath,String outPath){
        try {
            //读取的源文件
            FileInputStream in =new  FileInputStream(inPath);
            //复制到文件
            FileOutputStream out =new FileOutputStream(outPath);
            byte[] b = new byte[100];
            int len = 0;
            while((len = in.read(b)) != -1){
                //参数1:是写的缓冲数组,参数2:从数组的哪个位置开始,参数3:获取的数组的总长度
                out.write(b,0,len);
            }
            //刷写到硬盘
            out.flush();
            out.close();
            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
【注】文件字节流非常通用,可以用来操作字符文档,还可以操作任何的其他类型文件(图片、压缩包等),因为字节流直接使用二进制。
5.文件字符流
文件字符流和文件字节流的差别
//建立一个流对象
FileInputStream in =new  FileInputStream("text.txt");
//创建一个临时存放数据的数组
 byte[] b = new byte[100];
//调用流对象方法将流中的数据读入到数组中
in.read(b)
    
/**
*文件字符输入流
*/
   
    //建立一个流对象
    FileReader fr = new FileReader("Test.txt");
	//创建一个临时存放数据的数组
	char[] ch = new char[1024];
	//调用流对象方法将流中的数据读入到数组中
   fr.read(ch);
【注】字符流只适合操作字符文档
6.处理流之一:缓冲流
 (1) 缓冲流就是先把数据缓冲内存里,在内存中去做io操作。
 (2)缓冲字节输入流
 /**
     * 缓冲字节输入流
     * testBUfferedInputStream
     */
    public static void testBUfferedInputStream() throws Exception{
        //文件字节输入流对象
        FileInputStream in = new FileInputStream("F:/yuanma/src/tt.txt");
        //把文件字节输入流放到缓冲字节输入流对象
        BufferedInputStream br = new BufferedInputStream(in);
        byte[] b = new byte[10];
        int len = 0;
        while((len = br.read(b)) != -1){
            System.out.println(new String(b,0,len));
        }
        br.close();
        in.close();
    }
 (3)缓冲字节输出流
  /**
     * 缓冲字节输出流
     * BUfferedOutputStream
     */
    public static void testBUfferedOutputStream()throws Exception{
        //创建字节输出流对象
        FileOutputStream out =new FileOutputStream("F:/yuanma/src/tt1.txt");
        //把字节输出流方法缓冲字节输出流
        BufferedOutputStream bo = new BufferedOutputStream(out);
        String s = "hello word!";
        //写到内存中
        bo.write(s.getBytes());
        bo.flush();
        bo.close();
        out.close();
    }
 (3)缓冲实现文件的复制
/**
     * 缓冲流实现文件的复制
     */
    public static void copyFile() throws Exception{
        //缓冲输入流
        BufferedInputStream br = new BufferedInputStream(new FileInputStream("F:/yuanma/src/tt1.txt"));
        //缓冲输出流
        BufferedOutputStream bo = new BufferedOutputStream(new FileOutputStream("F:/yuanma/src/tt2.txt"));
        byte[] b = new byte[1024];
        int len = 0;
        while((len = br.read(b)) != -1){
            bo.write(b,0,len);
        }
        bo.close();
        br.close();
    }
7.处理流之二:转换流
 (1)定义:可以把字节流转换为字符流,当字节流中的数据都是字符的时候,用转换流转为字符流处理效率更高。
/**
         * 所有文件都是有编码格式
         *TXT和java文件一般来讲三种编码
         * ISO8859-1,西欧编码,是纯粹英文编码,不适应汉字
         * GBK和UTF-8,这两编码是适用于中文和英文
         *我们一般使用UTF-8编码
         */
 (2)转换字节输入流为字符输入流
 /**
     * 转换字节输入流为字符输入流
     * 注意在转换字符流使,设置的字符集编码要与读取的文件一致
     */
    public static void testInputStreamReader() throws Exception{
        FileInputStream fs = new FileInputStream("F:/yuanma/src/test/tt5.txt");
        //把字节流转换为字符流,参数1:字节流,参数2:是编码
        InputStreamReader in = new InputStreamReader(fs,"GBK");
        char[] c = new char[100];
        int len = 0;
        while((len = in.read(c)) != -1){
            System.out.println(new String(c,0,len));
        }
        in.close();
        fs.close();
    }
 (2)转换字节输出流为字符输出流
    /**
     *转换字节输出流为字符输出流
     * @throws Exception
     */
    public static void tesstOutputStreamWrite() throws Exception{
        FileOutputStream out = new FileOutputStream("F:/yuanma/src/test/tt6.txt");
        OutputStreamWriter os = new OutputStreamWriter(out,"UTF-8");
        os.write("年号你好");
        os.flush();
        os.close();
        out.close();
    }
8.处理流之三:标准输入输出流
 (1)标准输入流
    /**
     * 标准的输入流
     * @throws Exception
     */
    public static void testSystemIn() throws Exception{
        //创建一个接收键盘输入数据的输入流
        InputStreamReader is = new InputStreamReader(System.in);
        //把输入流放入缓冲流
        BufferedReader br = new BufferedReader(is);
        String str = "";//定义一个接收数据的字符串
        while((str = br.readLine()) != null){
            System.out.println(str);
        }
        br.close();
        is.close();
    }
 (2)案例
 /**
     * 把控制台输入的内容写到指定的TXT文件中,当接受到的字符串为over时,结束程序的运行
     */
    public static void write2TXT() throws Exception{
        //创建一个接收键盘输入数据的输入流
        InputStreamReader is = new InputStreamReader(System.in);
        //把输入流放入缓冲流
        BufferedReader br = new BufferedReader(is);
        BufferedWriter out = new BufferedWriter(new FileWriter("F:/yuanma/src/test/tt7.txt"));
        String line = "";
        while ((line = br.readLine()) != null){
            if(line.equals("over")){
                break;
            }
            //读取的每一行都写到txt中
            out.write(line);
        }
        out.flush();
        out.close();
        br.close();
        is.close();
    }
9.处理流之四:打印流(了解)
10.处理流之五:数据流(了解)
 (1)数据流,专门用来做基本数据类型的读写
 (2)数据输出流
 /**
     * 数据输出流
     * 用数据输出流写到文件中的基本数据类型的数据,是乱码的,不能直接辨认,需要数据输入流来读取
     */
    public static void tsetDataOutputStream() throws Exception{
        DataOutputStream out = new DataOutputStream(new FileOutputStream("F:/yuanma/src/test/tt8.txt"));
//        out.writeBoolean(true);
//        out.writeDouble(1.35d);
        out.writeInt(100);
        out.flush();
        out.close();
    }
 (3)数据的输入流
/**
     * 数据的输入流
     * 用数据输入流读取数据输出流写到文件中的数据时,要保证使用和当时写的数据类型一致的类型来读取
     * 也就是写的时候时writeInt,读的时候就是readInt
     */
    public static void testDataInputStream() throws Exception{
        DataInputStream in =new DataInputStream(new FileInputStream("F:/yuanma/src/test/tt8.txt"));
        System.out.println(in.readInt());
        in.close();
    }
11.处理流之六:对象流
 (1)用于存储和读取对象的处理流
 (2)序列化:用ObjectOutputStream将一个Java对象写入IO流中。
 反序列化:用ObjiectInputStream类从IO流中恢复该Java对象。
 序列化与反序列化针对的是对象的各种属性,不包括类的属性。
/**
 * 序列化与反序列化
 * 对象的序列化与反序列化使用的类要严格一致,包名、类名、类机构等等都要一致
 */
public class tset05 {
    public static void main(String[] args){
        try {
//            tset05.testSerialize();
            tset05.testDeserialize();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 对象的序列化
     * @throws Exception
     */
    public static void testSerialize()throws Exception{
        //定义对象的输出流,把对象序列化之后的流放到指定的文件中
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("F:/yuanma/src/test/tt9.txt"));
        Person p = new Person();
        p.name = "zhangsan";
        p.age = 11;
        out.writeObject(p);
        out.flush();
        out.close();
    }
    /**
     * 对象的反序列化
     */
    public static void testDeserialize() throws Exception{
        //创建对象的输入流,从指定的文件中把对象序列化后的流读取出来
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("F:/yuanma/src/test/tt9.txt"));
        Object obj = in.readObject();
        Person p =(Person)obj;
        System.out.println(p.name);
        System.out.println(p.age);
        in.close();
    }
}
12.RandomAccessFile类
【注】如果是在文件开头或者中间的某个位置开始写的话,就会覆盖掉等长度的内容
    /**
     * 随机读文件
     */
    public static void testRandomAccessFileRead()throws Exception{
        //参数1:文件路径 参数2:指定的访问模式
        //r:以只读的方式打开
        //rw:打开以便读取和写入
        //rwd:打开以便读取和写入,同步文件内容更新
        //rwa:打开以便读取和写入,同步文件内容和元数据的更新
        RandomAccessFile ra = new RandomAccessFile("F:/yuanma/src/test/tt10.txt","r");
        ra.seek(8);//设置读取文件内容的起始点
        byte[] b = new byte[1024];
        int len = 0;
        while((len = ra.read(b)) != -1){
            System.out.println(new String(b,0,len));
        }
    }
    /**
     * 随机写
     */
    public static void testRandomAccessFileWrite()throws Exception{
        RandomAccessFile ra = new RandomAccessFile("F:/yuanma/src/test/tt10.txt","rw");
//        ra.seek(6);//设置写的起始点,0代表从头写
        ra.seek(ra.length());//表示从末尾写,追加
        ra.write("你好".getBytes());
        ra.close();
    }
}
第十章 反射
10.1概念
1.反射前提
 java已经加载过这个类,就可以通过类名来寻找这个类的所有相关信息。
2.反射(Reflection)
 动态语言的关键,反射机制允许程序在执行器借助于Reflection API取得任何内部类的内部信息,并能直接操作任意对象的内部属性及方法。
10.2class类
1.常用方法
2.通过反射调用类的完整结构
 (1)获取父类和接口
package test01;
public class test1 {
    public static void  main(String[] args){
        try {
            //通过包名、类名的字符串,调用Class.forName方法获取指定类的Class实例
            Class clazz = Class.forName("test01.Student");
            //获取父类
            Class superClazz = clazz.getSuperclass();
            System.out.println(superClazz.getName());
            //获取当前类的所有接口
            Class[] interfaces = clazz.getInterfaces();
            for(Class c : interfaces){
                System.out.println("接口:"+c.getName());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
 (2)获取类的全部构造器
package test01;
import java.lang.reflect.Constructor;
public class test1 {
    public static void  main(String[] args){
        try {
            //获取构造器
            //获取所有共有的构造方法
            Constructor[] cons = clazz.getConstructors();
            for(Constructor c : cons){
                System.out.println("构造方法:"+c.getName());
                System.out.println("构造方法:"+c.getName()+"的修饰符是:"+c.getModifiers());
                Class[] paramClazz = c.getParameterTypes();
                for(Class pc : paramClazz){
                    System.out.println("构造方法"+c.getName()+"的参数类型是:"+pc.getName());
                }
            }
            //获取所有的构造方法,1代表共有,2代表私有
            Constructor[] cons1 = clazz.getDeclaredConstructors();
            for(Constructor c : cons1){
                System.out.println("构造方法:"+c.getName());
                System.out.println("构造方法:"+c.getName()+"的修饰符是:"+c.getModifiers());
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
 (3)通过反射创建对象
package test01;
import java.lang.reflect.Constructor;
public class test1 {
    public static void  main(String[] args){
        try {
            //通过包名、类名的字符串,调用Class.forName方法获取指定类的Class实例
            Class clazz = Class.forName("test01.Student");
            try {
                //调用Student类的无参共有构造
                Object obj = clazz.newInstance();
                Student stu = (Student)obj;
                //指定获取有一个参数并且为string类型的公有的构造方法
                Constructor c = clazz.getConstructor(String.class);
                Student stu1 = (Student)c.newInstance("第一中学");
                System.out.println(stu1.school);
                //同构反射机制,可以强制调用私有的构造方法
                //指定获取有两个参数并且为string和int类型的私有的构造方法
                Constructor c = clazz.getDeclaredConstructor(String.class,int.class);
                //解除私有的封装,下面就可以对这个私有方法强制调用
                c.setAccessible(true);
                Student stu = (Student)c.newInstance("zhanghsan",12);
            } catch (Exception e) {
                e.printStackTrace();
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
 (4)通过反射调用类中的指定方法、属性
                /**
                 * 注意:下面不论是反射调用setInfo还是test方法
                 * 都调用的obj对象的方法,obj对象实际上就是student对象
                 */
                //获取无参构造
 				Class clazz = Class.forName("test01.Student");
                Constructor con = clazz.getConstructor();
                //使用无参构造创建对象
                Object obj = con.newInstance();
                //得到名称setInfo的方法
                Method m = clazz.getMethod("setInfo", String.class, String.class);
                //参数1是需要实例化的对象,后面的参数是调用当前的方法实际参数
                m.invoke(obj,"zhangsan","第一中学");
                //调用私有方法
                Method m1 = clazz.getDeclaredMethod("test", String.class);
                m1.setAccessible(true);
                m1.invoke(obj,"lisi");
3.java动态处理
 (1)接口
package test02;
public interface ITestDemo {
    public void test1();
    public void test2();
}
 (2)实现接口
package test02;
public class TestDemoImpl implements ITestDemo{
    @Override
    public void test1() {
        System.out.println("执行Test1方法");
    }
    @Override
    public void test2() {
        System.out.println("执行Test2方法");
    }
}
 (3)实现代理类
package test02;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class ProxyDemo implements InvocationHandler{
    Object obj;//被代理的对象
    public ProxyDemo(Object obj){
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName()+"方法开始执行");
        //执行的是指定代理对象的指定方法
        Object result = method.invoke(this.obj,args);
        System.out.println(method.getName()+"方法执行完毕");
        return null;
    }
}
 (4)测试
package test02;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class test2 {
    public static void main(String[] args){
        ITestDemo test = new TestDemoImpl();
        /**
         * 如果一个对象想要通过Proxy.newProxyInstance方法代理
         * 那么这个对象的类一定要有相应的接口
         * 就像本类中的ITestDemo接口和TestDemoImpl
         */
        test.test1();
        test.test2();
        System.out.println("***************************");
        /**
         * 需求:
         * 在执行test1和test2前打印开始执行
         * 执行完后打印执行结束
         */
        InvocationHandler handler = new ProxyDemo(test);
        /**
         * Proxy.newProxyInstance(ClassLoader(),interfaces,h)
         * 参数1是代理对象的类加载器
         * 参数2是被代理的对象的接口
         * 参数3是代理对象
         *
         * 返回的值成功被代理后的对象
         */
        ITestDemo t = (ITestDemo) Proxy.newProxyInstance(handler.getClass().getClassLoader(),test.getClass().getInterfaces(),handler);
        t.test1();
        t.test2();
    }
}
第十一章 线程
11.1基本概念
1.概念
 程序:未完成某种任务,用某种语言编写的一组指令的集合。
 线程:程序的一次执行过程,或是正在运行的一个程序
 进程:进程可进一步细化为线程,是一个程序内部的一条执行路径,若一个程序可同时执行多个线程,就是支持多线程的。
11.2多线程的创建和启动
1.构造方法
通过继承Threa类实现多线程
package test03;
/**
 * 通过继承Threa类实现多线程
 */
public class TestThread extends Thread{
    @Override
    public void run(){
        System.out.println("多线程运行的代码");
        for(int i = 0;i < 5; i++){
            System.out.println("这是多线程的逻辑代码:"+i);
        }
    }
}
package test03;
public class Test {
    public static void main(String[] args){
        Thread t0 = new TestThread();
        t0.start();//启动线程
        System.out.println("*******************");
        System.out.println("*******************");
        System.out.println("*******************");
        /**
         * 从控制台多次运行main方法
         * 发现main方法中打印的3行与开启线程运行run方法中打印的是混合的
         * main方法执行t.start()方法开启多线程之后,就相当于在main方法之外开启一个直流
         * 这个时候t0.start之后的main方法的其他代码的运行就与run方法运行无关了
         * 就像两条河流,各走各的
         * 控制台输出的结果就是两条并行程序的运行结果综合,这个结果要拆开两部分看
         * 各自保持自己的输出顺序
         */
    }
}
通过实现Runnable接口实现多线程
package test03;
/**
 * 通过实现Runnable接口实现多线程
 */
public class TestRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"多线程运行的代码");
        for(int i = 0;i < 5; i++){
            System.out.println(Thread.currentThread().getName()+"这是Runnable多线程的逻辑代码:"+i);
        }
    }
}
package test03;
public class Test {
    public static void main(String[] args){
//      t0.start();//启动线程
//        Thread t3 = new Thread(new TestRunnable());
//        t3.start();
        Thread t4 = new Thread(new TestRunnable(),"t-1");
        t4.start();
        Thread t5 = new Thread(new TestRunnable(),"t-2");
        t5.start();
        System.out.println("*******************");
        System.out.println("*******************");
        System.out.println("*******************");
    }
}
2.继承方式和实现方式的联系与区别
【区别】
 继承Thread:线程代码放在Thread子类run方法中。重写run方法
 实现Runnable:线程代码放在接口的子类的run方法中。实现run方法
一般使用实现run方法
【实现的好处】
 (1)避免了单继承的局限性。
 (2)多线程可以共同享用一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。
3.多线程的好处
 (1)提高引用程序的响应。对图形化界面更有意义,可增强用户体验。
 (2)提高计算机系统CPU的利用率。
 (3)改善程序结构。将即长又复杂的进程分为多个线程,独立运行,利于理解和修改。
4.Thread的方法
package test03;
public class Test1 {
    public static void main(String[] args){
        TestRun run0 = new TestRun();
        TestRun run1 = new TestRun();
        Thread t0 = new Thread(run0);
        Thread t1 = new Thread(run1);
        //设置优先级
//        t0.setPriority(1);
//        t1.setPriority(10);
        t0.start();
        t1.start();
//        t0.setName("线程t0");//设置线程的名称
//        System.out.println(t0.getName());
//        System.out.println(t1.getName());
        /**
         * 优先级:就是那个线程有较大的概率被执行
         * 优先级用数组1-10来表示,数字越大优先级越高,默认为5
         */
        //获取优先级
//        System.out.println("t0的优先级"+t0.getPriority());
        System.out.println("***************1");
        System.out.println("***************2");
        System.out.println(t1.isAlive());//判断当前线程是否存活
//        t1.stop();强制线程生命周期结束,强制停止此线程
        try {
            t0.join();//相当于在这块把t0的run的代码插入到这个位置执行
            /**
             * 就是阻塞当前的main方法,先不执行System.out.println("***************3");
             * 先执行join进来的线程代码
             * join的线程执行完毕之后在继续执行之前main方法阻塞的代码
             */
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("***************3");
    }
}
class TestRun implements Runnable{
    int count = 0;
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName() + "多线程运行的代码");
        for (int i = 0; i < 5; i++) {
//            try {
//                Thread.sleep(1000);//当前线程睡眠1000毫秒
//                //相当于当前的这个循环每隔1000毫秒执行一次循环
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//            if(i % 2 == 0){
//                //线程让步
//                Thread.yield();
//            }
            count++;
            System.out.println(Thread.currentThread().getName() + "这是Runnable多线程的逻辑代码:" + count);
        }
    }
11.4线程的生命周期
1.五种状态
 (1)新建:线程实例的创建
 (2)就绪:执行.start()方法之后
 (3)运行:run的代码开始运行
 (4)阻塞:类似堵车,run方法暂停,卡住run方法
 (5)死亡:线程完成了它的全部工作,执行.stop()方法或者断电或者杀掉线程被提前强制性的中止

11.5线程的同步
1.synchronized的使用方法
package test03;
public class Test2 {
    public static void main(String[] args){
        //定义账户对象
        Account a = new Account();
        //多线程对象
        User u_weixin = new User(a,2000);
        User u_zhifubao = new User(a,2000);
        Thread weixin = new Thread(u_weixin,"微信");
        Thread zhifubao = new Thread(u_zhifubao,"支付宝");
        weixin.start();
        zhifubao.start();
    }
}
class Account{
    public static int money = 3000;
    /**
     * 提款,判断账户金额够不够
     * 多线程调用,线程共享资源时,一个线程执行这个方法没有完毕时,另一个线程又执行这个方法
     * 解决方法:先让一个线程执行完毕,在执行另一个线程
     * 使用synchronized同步锁来完成
     * 可直接在方法上加上synchronized关键字
     * 在普通方法上加synchronized,锁的时整个对象,不是某一个方法
     * 不同的对象就是不同的锁,普通方法加synchronized,线程使用不同的此方法的对象,还有共享资源的问题
     * @param m
     */
    public synchronized void drawing(int m){
        String name = Thread.currentThread().getName();
        if(money < m){
            System.out.println(name+"操作,账户金额不足"+money);
        }else {
            System.out.println(name+"操作,账户原有金额:"+money);
            System.out.println(name+"操作,取款金额:"+m);
            money = money - m;
            System.out.println(name+"操作,取款后余额:"+money);
        }
    }
}
class User implements Runnable{
    Account account;
    int money;
    public  User(Account account,int money){
        this.account = account;
        this.money = money;
    }
    @Override
    public void run() {
        account.drawing(money);
    }
}
2.线程的死锁问题
 (1)死锁:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁。
 (2)解决方法:
 专门的算法、原则,比如枷锁顺序一致;
 经量减少同步资源的定义,尽量避免锁未释放的场景。
11.6线程通信
1. 三种方法
 wait():挂起当前线程;
 notify():唤醒正在等待资源优先级最高的线程;
 notifyall():唤醒所有正在等待资源的线程。
【注】这三个方法只能用在有同步锁的方法或者代码块中。
2.用法
package test03;
public class Test2 {
    public static void main(String[] args){
        //定义账户对象
        Account a = new Account();
        //多线程对象
        User u_weixin = new User(a,2000);
        User u_zhifubao = new User(a,2000);
        Thread weixin = new Thread(u_weixin,"微信");
        Thread zhifubao = new Thread(u_zhifubao,"支付宝");
        weixin.start();
        zhifubao.start();
    }
}
class Account{
    public static int money = 3000;
    public synchronized void drawing(int m,Account a){
        String name = Thread.currentThread().getName();
       
        /**
         * 如果时微信操作,等待
         */
        if(name.equals("微信")){
            try {
                a.wait();//当前进程进入阻塞状态
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        
        if(money < m){
            System.out.println(name+"操作,账户金额不足"+money);
        }else {
            System.out.println(name+"操作,账户原有金额:"+money);
            System.out.println(name+"操作,取款金额:"+m);
            money = money - m;
            System.out.println(name+"操作,取款后余额:"+money);
        }
        
        if(name.equals("支付宝")){
            a.notify();//唤醒当前优先级最高的线程,进入就绪状态
        }
        
    }
}
class User implements Runnable{
    Account account;
    int money;
    public  User(Account account,int money){
        this.account = account;
        this.money = money;
    }
    @Override
    public void run() {
        account.drawing(money,account);
    }
}
11.7经典例题:生产者/消费者问题
package test03;
/**
 * 生产者/消费者问题
 */
public class Test3 {
    public static void main(String[] args){
        Clerk c = new Clerk();
        //生产时不消费,消费时不生产
        //生产者
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (c){
                    while (true){//无限循环代表无限的生产次数
                        if(c.productNum == 0){//产品数为0开始生产
                            System.out.println("生产数为0,开始生产");
                            while (c.productNum < 4){
                                c.productNum++;//生产产品
                                System.out.println("库存:"+c.productNum);
                            }
                            System.out.println("生产数为"+c.productNum+",结束生产");
                            c.notify();//唤醒消费者线程
                        }else {
                            try {
                                c.wait();//生产者等待
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        },"生产者").start();
        //消费者
        new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (c){
                    while (true){//无限循环代表无限的消费次数
                        if(c.productNum == 4){//产品数为4开始消费
                            System.out.println("生产数为4,开始消费");
                            while (c.productNum > 0){
                                c.productNum--;//消费产品
                                System.out.println("库存:"+c.productNum);
                            }
                            System.out.println("消费数为"+c.productNum+"结束消费");
                            c.notify();//唤醒生产者线程
                        }else {
                            try {
                                c.wait();//消费者等待
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }
            }
        },"消费者").start();
    }
}
class Clerk{
    public static int productNum = 0;
}
 
                    
                 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号