三个月呕心巨制!Java必备知识点

Java基础

数组常见异常

  • ArrayIndexOutofBoundsException
public static void main(String[] args) {
		int[] i = new int[10];
		i[10]= 99;
    
  • NullPointerException

第一种:

boolean[] b = new boolean[3];
b = null;
System.out.println(b[0]);

第二种:

String[] str = new String[4];
System.out.println(str[3].toString());

第三种:

int[][]j = new int[3][];
j[2][0] = 33;

array复制

int[] array1, array2;
array1 = new int[] { 2, 3, 8};
/* 
array2 = array1
error:如果修改array2会同时修改1,因为这样只是传递了地址给2
*/
array2 = new int[array1.length];
for (int i = 0; i < array1.length; i++){
    array2[i] = array1[i];
}

array元素反转

int[] arr = new int[]{ 9, 88, 5};
for(int i = 0;i < arr.length/2;i++){
    int temp = arr[i];
    arr[i] = arr[arr.length - 1 - i];
    arr[arr.length - 1 - i] = temp;
}//第一种
/*第二种
for(int x = 0,y = arr.length - 1;x < y;x++,y--){
	int temp = arr[x];
	arr[x] = arr[y];
	arr[y] = temp;
}
*/

数组排序

  • 冒泡

    public static void main(String[] args) {
    			int[]arr = new int[]{49,343,45,87,3,13,67};
    			for(int i = 0; i < arr.length -1; i++){
    				for(int j = 0; j < arr.length -1 - i; j++){
    					if (arr[j] > arr[j+1]) {
    						int temp = arr[j];
    						arr[j] = arr[j + 1];
    						arr[j + 1] = temp;
    		           }
    		       }
    		    }
    		    System.out.println("从小到大排序以后:");
    		    for(int i = 0; i < arr.length; i++){
    		    	System.out.println(arr[i] + "\t");
    		    }
    		}
    
  • 直接选择顺序

    public static void main(String[] args) {
    		int[]arr = new int[]{49,343,45,87,3,13,67};
    		for(int i = 0; i < arr.length - 1; i++) {
    			int t = i;//默认i是最小
    			for(int j = i; j < arr.length; j++) {
    				//一旦在i后发现存在比i小的元素,记录那个下角标
    				if(arr[t] > arr[j]) {
    					t = j;
    				}
    			}
    			if(t != i) {
    				int temp = arr[t];
    				arr[t] = arr[i];
    				arr[i] = temp;
    			}
    		}
    		 System.out.println("从小到大排序以后:");
    		    for(int i = 0; i < arr.length; i++){
    		    	System.out.println(arr[i] + "\t");}// TODO Auto-generated method stub
    
    	}
    

面向对象

总结

overload重载

同一个类中,方法名相同,而参数列表不同(类型/个数),与返回类型无关

class Overload{
    public int getSum(int i,int j){
        return i + j;
    }
    public int getSum(int i, int j, int k){
        return i + j + k;
    }
    public int getSum(double a, double b){
        return a * b;
    }
    public void getSum(double a, double b, double c){
        System.out.println(a + b + c);
    }
}
class Overload{
    public void method(int i, String j){
        
    }
    public void method(String j, int i){
        
    }
}

匿名类对象

创建的类的对象是匿名的

  • 只需要一次调用类的对象
p.printAreas(new Circle(), 6);
//System.out.println(c.getRadius);

可变个数的形参的方法(数据类型要一样)

  • 调用时, 个数从0开始
// 以下三个sayHello()仍为overload
public void sayHello(String str1){
    System.out.println("hello" + str1);
}
public void sayHello(){
    for(int i = 0; i < args.length; i++){
        System.out.println(args[i]);
    }
}
// 可变个数形参
public void sayHello(String... args){
    for(int i = 0; i < args.length; i++){
        System.out.println(args[i]);
    } 
}
  • 若方法中存在可变个数的形参,一定要声明在最后
public void sayHello(int i, String... args){
    for(int i = 0; i < args.length; i++){
        System.out.println(args[i]);
    } 
}
  • 一个方法只能有一个可变个数的形参

方法参数传递

pass by value 值传递:

  • argument是primitive: 将parameter的值传递给argument的基本数据类型变量
  • argument是reference: 将reference的值(对应堆空间的对象实体的首地址值) 传递给argument的引用数据类型变量

面向对象特征之一: 封装(Encapsulation)

问题: 不让对象直接作用属性,而是通过“方法.属性”来控制对象对属性的访问

  • 封装:
    1. 将类的属性私有化
    2. 提供公共方法来实现调用
public class TestAnimal {
    public static void main(String[] args){
        Animal a1 = new Animal();
        a1.setLegs(4);
        a1.setname("花花");
        a1.getLegs();
        a1.getName;
    }
}

class Animal{
    private String name;
    private int legs;
    //private 修饰的属性只能在本类中来调用,出了本类,只能用公共方法来调用
    public void setLegs(int l){
        if(l > 0 && l % 2 ==0){
            legs = l;
        }else{
            System.out.println("您输入的数据有误");
        }
    }
    public void setName(String n){
        //...
        name = n;
    }
    //设置类的属性
    public int getLegs(){
        return legs;
    }    
    public String getName(){
        return name;
    }
    //获取类的属性
}
  • class/ method 权限修饰符: public protected default private
修饰符类内部同一个包子类任何地方
privateyes
(default)yesyes
protectedyesyesyes
publicyesyesyesyes

class 只能用(default)和 public

类的成员之三: 构造器(constructor)

前两个是属性(field),方法(method)

作用:

1. 创建对象
2. 给创建的对象的属性赋值
  • 如何声明: 权限修饰符 类名 (形参) { }
  • 设计类时, 若不显式声明类的构造器, 程序会默认提供一个空参的构造器
  • 有显式的定义类的构造器, 不在提供默认的构造器
  • 类的多个构造器之间构成重载
public class TestPerson{
    public static void main(String[] args){
        //Person p1 = new Person(); 默认的空参
        Person p2 = new Person("Jack", 23);
        System.out.println(p2.getName);
        System.out.println(p2.getAge);// Jack  0
        Person p3 = new Person("Rose", 22);
        System.out.println(p3.getName + "\t" + p3.getAge); //Rose	22 
    }
}

class Person{
  	// 属性
    private String name;
    private int age;
    
    // 构造器 
    public Person(String n){
        name = n;
    }
    public Person(int m){
        age = m;
    }
    public Person(String n, int m){
        name = n;
        age = m;
    }
    // 方法
    public void setName(String n){
        name = n;
    }
    public void setAge(int m){
        age = m;
    }
    public getName(){
        return name;
    }
    public getAge(){
        return age;
    }
   
}

类对象的属性赋值先后: 1. 默认初始化 2. 显式 3. 构造器 4. “对象.方法()”

this

  • this.当前对象或当前正在创建的对象

  • 可修饰 属性, 方法, 构造器

  • 在构造器中, “this(argument)”: 调用当前类重载的指定构造器

    • 在构造器内部必须是首行!
    • 若一个类中有n个构造器, 那么最多有 n - 1 个构造器中使用this(argument), 否则会出现环路
class Person{
    private int age;
    private String name;
    
    public Person(String name){
        this.name = name;
    }
    public Person(int age){
        this.age = age;
    }
    // this.age: 当前正在创建的对象
    public Person(int age, String name){
        this(age);// 显式的调用当前类的重载的指定构造器
        this.name = name;// this(name);
    }
    
    public void setAge(int age){
        this.age = age;
    }
    //this.age: 当前对象
    public void info(){
        System.out.println("age:" + this.age);
        this.show();// this.show(): 当前方法
    }
    public void show(){
        System.out.println("我是一个人,我的年龄是:" + this.age);
    }
}

package

  • 声明源文件所在的包, 写在程序的第一行

  • 每**"."**一次, 表示一层文件目录

    package study.qinghu.java
    
  • 小写

import

  • 显式导入指定包下的类或接口

  • 若导入java.lang包下的,如: System, String, Math, etc, 不用显示声明

  • “.*”

    import java.util.*
    
  • 同名类的导入, 如: 在util包和sql包下同时存在Date类

    import java.util.*
      ...
      Date d = new Date();
    	java.sql.Date d1 = new java.sql.Date(23423428L);
    
  • import static 表示导入指定类的static的属性/方法

  • 只能导入包下的所有类/接口, 不能导入子包下的类或接口

面向对象特征之二:继承(inheritance)

public class Person{
    public void eat{
        System.out.println("吃饭");
    }
}
public class Worker extends Person{
    public static void main(String[] args) {
        Student s = new Student();
        s.eat();
    }
}
  • 当父类中有private class或method,子类获取的到,但由于封装性,使得子类不能直接调用
  • 单继承: 子类只能extends一个父类, 一个父类可以有多个子类

override重写

对父类重名的类进行重写. 修饰符 返回值类型 方法名 (参数列表) { }

public class Worker extends Person{
    public void eat() {
        System.out.println("工人吃饭");
    }
}
  • 原因: 子类继承父类后, 若父类的方法对子类不适用, 那么子类可以对父类的方法覆盖

  • 规则:

    1. 子类方法的" 返回值类型 方法名 (参数列表) { }" 与父类方法一样
    2. 子类方法的修饰符 >= 父类方法
    3. 子类方法抛的异常 <= 父类
    4. 子父类的方法必须同为static或同为非static

super

  • 父类 属性, 方法, 构造器
  1. 当子类与父类有同名的属性时, 可以通过"super.属性" 显式的调用父类中同名的属性; "this.属性"调用子类中同名的属性

  2. 当子类重写父类的方法后, "super.方法"在子类中显式调用父类中被重写的方法

  3. 在子类中使用"super(形参列表)"来显式的调用父类中指定的构造器

    • 在构造器中, "super(形参列表)"必须声明在首行. 所以super和this只能出现其中一个
    • 在构造器中, 不显式调用"this(argument)"或"super(argument)"任何一个, 默认调用的是父类空参的构造器
  4. 建议: 设计一个类时, 尽量要提供一个空参的构造器

面向对象特征之三: 多态性

  1. 多态性

    1. 方法的重载和重写

    2. 子类对象的多态性

  2. 子类对象的多态性使用前提:

    1. 要有类的继承
    2. 子类对父类方法的重写
  3. 编译和运行
    编译时, “看左边”, 将此引用变量理解为父类的类型
    运行时, “看右边”, 关注真正的对象的实体: 子类的对象. 执行的方法就是子类重写的.

  4. 向下转型:

    1. 强转符: Man m1 = (Man) p1;

    2. 保证不报错ClassCastException, 最好向下转型前, 进行判断: if (p1 instanceof Woman){ }

  5. 子类对象的多态性, 并不适用于属性. 即"看左边"

public class JavaPolymorphism {
    public static void main(String[] args) {
        ...
        //子类对象的多态性,父类的引用指向子类对象
        Person p1 = new Man();//向上转型
        //虚拟方法调用: 通过父类的引用指向子类的对象实体, 实际执行的是子类重写父类的方法
        p1.eat();
        p1.walk();
        //p1.shaving(); 编译不通过, 因为Person类里没有Man类的方法
        Man m1 = (Man)p1;//向下转型, 使用强转符
        m1.shaving();
//      Women w = (Woman)p1; 
//      w1.shopping;编译通过, 运行报错
     	
        //instanceof:返回值boolean
        if (p1 instanceof Woman) {
            Woman w1 = (Woman)p1;
            w1.shopping();
        }
         if (p1 instanceof man) {
            man m1 = (man)p1;
            m1.shaving();
        }
    }
}

object类

  • java.lang.Object 类, 是所有类的根父类
  • 仅有一个空参构造器: public Object() {}
  • method:
    • equals()

      1. 只能比较引用类型变量
      2. 比较两个变量的地址值是否相等
Person p1 = new Person();
Person p2 = new Person();
System.out.println(p1.equals(p2));//false
System.out.println(p1 == p2);//false

​ 3. String,Package类 ,File类 , Data类 重写Object类的equals()方法, 比较两个对象的"内容"是否完全相同

String str1 = new String("AA");
String str2 = new String("AA");
String str3 = "AA";
String str4 = "AA";
System.out.println(str1 == str2);//false
System.out.println(str1.equals(str2));//true
System.out.println(str3 == str4);// true "AA"在常量池
System.out.println(str1.equals(str3));// true
 		4. 自定义一个类, 希望比较两个对象的属性值都相同的情况下返回true, 就需要重写equals(Object obj)方法
//自定义
public boolean equals(Object obj){
    if (this == obj){
        return true;
    }
    if (obj instanceof Person){
        Person p = (Person)obj;
        return this.equals(p.name) == p.name && this.age == p.age;
    } else {
        return false;
    }
}

== :

  • primitive: 比较值
  • reference: 比较地址值

toString方法

  • java.lang.Object.toString:

    public String toString() {
        return getClass().getName() + "@" + Interger.toHexString(hashCode());
    }
    
    • 当打印一个对象的引用时, 默认调用的是这个对象的toString()方法

    • 当打印的对象所在类没有重写Object中toString()时, 那么调用的是Object定义的返回对象所在的类及对应的堆空间对象的首地址值

    • 常常如下重写了toString(), 将对象的属性信息返回

      public String toString() {
          return "Person: name = " + name + " age= " + age;
      }//手动
      
      //自动
      
    • String, Wrapper, File, Data, 已经实现了Object中toString() override

Wrapper包装类

PrimitiveWrapper
booleanBoolean
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
  • Wrapper 默认null
  • autoboxing/ unboxing
  • Wrapper与Primitive, String相互转化

    @Test
    public void test2() {
        //Primitive, Wrapper ---> String: 
        int i1 = 10;
        String str1 = i1 + "";//"10" 方法1
        
        Integer i2 = i1;
        String str2 = String.valueOf(i2);//方法2: 调用String override的valueOf(Xxx x)方法
        String str3 = String.valueOf(true);
        
        //String--->Primitive, Wrapper:
        int i3 = Integer.parseInt(str2);//方法1:  调用Wrapper的静态的parseXxx(String)方法
        boolean b1 = Boolean.parseBoolean(str3);
        
    }
    
    @Test//Primitive <---> Wrapper
    public void test1(){
        int i = 0;
        System.out.println(i);
        boolean a = false;
        
        Integer i1 = new Integer(i);
        System.out.println(i1.toString());
        Float f = new Float(22.5F);
        //Float f = new Float("22.5F");
        System.out.println(f);
        
        //java.lang.NumberFormatException
        //i1 = new Integer("12abc");
        //System.out.println(i1);
        
        Boolean b = new Boolean("false");
        System.out.println(b);//"false"
        //Boolean: 当形参是"true" 返回true, 除此之外返回false
        Boolean b1 = new Boolean("trueabc");
        System.out.println(b1);// "false"
        
        Order o = new Order();
        System.out.println(o.c);//null
        
        //Wrapper ---> Primitive: 调用包装类Xxx的XxxValue()方法
        int i2 = i1.intValue();
        System.out.println(i2);
        
        //JDK 5.O后, autoboxing,unboxing
        Integer i3 = 30;//autoboxing
        Boolean jj = false;
        
        int i4 = i3;//unboxing
    }
    
    class Order{
        Boolean c;
    }
    

static

static修饰属性, 方法, *代码块, *内部类

  • static修饰属性(类变量)

    • 由类创建的所有的对象, 都共用这一个属性, 存在静态域中. 对此属性进行修改, 会导致其他对象对此属性的调用.

      实例变量(非static修饰的变量,各个对象各自拥有一套副本)

    • 类变量随着类的加载而加载,早于对象, 且只一份

      实例变量(随着对象的创建而被加载)

    • 静态的变量可以直接通过"类.类变量"来调用, 也可以通过"对象.类变量"来调用, 但是"类.实例变量"不行.

  • static修饰方法(类方法)

    • 只能调用静态的属性和静态的方法, 非静态的方法能调用静态的属性和方法
    • static修饰的方法里不能有this|super
  • constructor 看作和方法一样

静态的结构(static的field method 代码块 内部类)生命周期比非静态结构长: 加载早于非静态, 被回收晚于非静态

static变量的内存结构图

应用:

利用静态的变量达到累加的效果, 因为静态的内容独一份,被多个对象所共用, 比如记录创建对象的次数/ 每个对象某个属性有关联

public class TestAccount {
    psvm{
        Account a1 = new Account("abc", 1000);
        Account a2 = new Account("CDF", 2000);
        sout(a1);
        sout(a2);
    }
}
class Account{
    private int id;//账号
    private String password;
    private double balance;
    private static double minbalance = 1;
    private static double rate = 0.05;//利率
    private static int init = 1000;//初始金额
    
    public Account(String password, double balance) {
        this.id = init++;
        this.password = password;
        this.balance = balance;
    }
    ...
}

类的成员之四: 代码块

  • 代码块只能有static修饰

  • 非静态代码块:

    • 对类的属性(静态||非静态)进行初始化
    • 可以有输出语句
    • 一个类中可以有多个代码块,多个代码块之间按照顺序结构执行
    • 每创建一个类的对象, 非静态代码块就加载一次
    • 非静态代码块的执行早于构造器

属性赋值的操作:

①默认的初始化

②显式的初始化||初始化块(此两结构按照顺序执行)

③构造器

——— 以上是对象的属性初始化的过程———

④通过方法对对象的相应的属性进行修改

  • 静态代码块
    • 可以有输出语句
    • 随着类的加载而加载, 而且只被加载一次
    • 多个静态代码块按照顺序执行, 均早于非静态
    • 静态代码块中只能执行静态的结构(类属性,类方法)
public class TestOrder {
    psvm {
        Order o1 = new Order();
        sout(o1);
        
        Order o2 = new Order();
        sout(o2);
    }
}
class Order{
    private int orderId = 1001;
    private String orderName;
    //静态代码块
    {
     	orderId = 1002;
        orderName = "AA";
        sout("我是非静态代码块1")
    }//我是非静态代码块1
     //Order[orderId = 1002, orderId = AA]
    static{
        sout("静态代码块3")
    }//静态代码块3
     //我是非静态代码块1
     //Order[orderId = 1002, orderId = AA]
    ...
}

final

  • 修饰类, 属性, 方法

    • final class: 不能被继承, eg. String, StringBuffer, System

    • final method: 不能被重写, eg. Object.getClass()

    • final field: 此属性是常量. 用大写字符, eg. final int L

      在哪赋值: ①不能默认赋值②可以显式赋值: 代码块, 构造器

    • 全局常量: 被static, final修饰, eg. Math.PI

      public static final double PI

diff: finally, finalize()

Abstract

  • 可以修饰类, 方法

  • 不能被实例化, 但可以定义构造器

    所有类都有构造器

  • 有抽象方法的一定是抽象类, 抽象类不一定有抽象方法

  • 若子类继承抽象类, 并重写了所有 的抽象方法, 则此类是"实体类", 即可以实例化;

    若子类继承抽象类, 并未重写了所有 的抽象方法, 则此类仍为抽象类.

public class TestAbstract {
    psvm {
        //Person p1 = new Person();
        //p1.eat;
        Student s1 = new Student();
        s1.eat;
    }
abstract class Person {
	String name;
    
    public Person() {
    }
    public Person(String name) {
        this.name = name;
    }
    //abstract method
    public abstract void eat();
    public abstract void walk();
}
    
class Student extends Person {
	public void eat() {
        sout("student eat");
    }
    public void walk() {
        sout("student walk");
    }     
}
}

总结: 抽象类作为多个子类的通用模版, 子类在抽象类的基础上拓展.

解决的问题:

  1. 当功能内部一部分实现是确定的, 一部分实现是不确定的. 把不确定的部分放在抽象类, 让子类重写
  2. 编写一个抽象父类, 父类提供子类的通用方法, 并把>= 一个方法留给子类实现.

interface 接口

  • interface是与class并行的
  • 接口看作特殊的抽象类, 包含常量, 抽象方法, 不能包含变量, 一般的方法.
  • 没有构造器, 所以不能创建对象
  • 定义的是一种功能, 可以被类实现(implements)
  • 实现接口的类, 必须重写其中所有 的抽象方法, 才能实例化, 否则仍为一个抽象类
  • 类能实现多个接口(Java中是单继承)
  • 接口与接口之间是继承
  • 只能被public, (default)修饰
public class TestInterface {
    
}

interface AA {
    //常量
    int I = 12//public static final int I = 12;所有常量都有这些修饰符,所以省略
    //int i;不能有变量
    
    //抽象方法
    void method1();//public abstract void method1);所有方法都有这些修饰符,所以省略
}

abstract class BB implements AA {

}
class DD {
        
}
interface MM {
    void method2();
}


//接口被类实现, 类能实现多个接口
class CC extends DD implements AA, MM {
    public void method1() {
        
    } 
    public void method2() {
        
    }
}

//接口继承接口
interface JJ extends AA, MM {
    void method1();
    void method2();
}

类的成员之五: 内部类

  1. 在类的内部再定义类, 外面的类:外部类. 里面的类: 内部类

  2. 分类:

    • 成员内部类: 声明在类的方法外
    • 局部内部类: 声明在类的方法里
  3. 成员内部类:

    • 外部类的成员:
      • 4个修饰符
      • static final
      • 可调用外部类的属性, 方法
    • 类的特点:
      • abstract
      • 还能在内部定义属性, 方法, 构造器
  4. 局部内部类:

掌握:

  • 如何创建成员内部类的对象
  • 如何区分调用外部类, 内部类的变量(尤其是变量重名时)
  • 局部内部类的使用

异常处理(Exception&Error)

common RuntimeException:

  • 空指针 NullPointerException

    @Test
    public void test1() {
        Person p = new Person();
        p = null;
        sout(p.toString());
    }
    
  • 数组下标越界 ArrayIndexOutOfBoundsException

    @Test
    public void test2() {
        int[] i = new int[10];
        sout(i[10]);
    }
    
  • 算术异常 ArithmeticException

    @Test
    public void test3() {
        int i = 10;
        sout(i / 0);
    }
    
  • 类型转换 ClassCastException

    @Test
    public void test4() {
        Object obj = new Date();Date向上转型为Object
        String str = (String)obj;将Object向下转型String, 但Date不支持
        //String str = (String)new Date();编译异常
    }
    

一旦出现异常, 下面的代码就不执行了

如何处理异常

  • 抓抛模型

    1. “抓”: 抓住上一步抛出来的异常类的对象.
    • try-catch-(finally)
    try {
    
    //可能出现异常的代码
    
    } catch (Exception e1) {
    
    //处理的方式1
    
    } catch (Exception e2) {
    
    //处理的方式2
    
    }
    finally {
    
    //一定要执行的代码
    }
    
    1. try内声明的变量,类似于局部变量, 出了try{}, 就不能被调用
      finally{ }可省略

    2. catch() 对异常对象的处理:

      • getMessage();
      • printStackTrace();
      1. 可以有多个catch(), try{} 中抛出的异常类从上往下匹配catch()中异常类的类型, 满足一个并执行完处理方式后就跳出其后多条catch(). 异常处理之后的代码可以执行

      2. catch()中多个异常类型是子父类, 子类必须放上面, 否则编译不通过

      3. finally{ }中的代码一定被执行, 不管try{}, catch() {}中是否有仍未处理的异常/ 是否有return

      4. try-catch可以嵌套

    • throws

      在方法声明处, 显式抛出该异常对象的类型.

   public staic void method() throws Exception{
     ...
   }

​ 2. “抛”: 当我们执行代码时,一旦出现异常,会在异常代码处生成一个对应的异常类型的对象,并将此对象抛出,且程序终止.(自动抛/手动抛)

此异常类的对象抛给方法的调用者

  • 手动抛throw+ 异常类的对象

    throw new RuntimeException("wrong");
    
    • 自定义异常类

      仿造RuntimeException

  • 子类重写父类方法, 抛出的异常类型 <= 被重写的方法抛的异常

集合

image-20200517221016723

Collection接口继承树

Collection接口

  • 方法
public class TestCollection {
    @Test
    public void testCollection1() {
        Collection coll = new Arraylist();
        //1. size();返回集合中元素个数
        sout(coll.size());
        //2. add(Object obj);添加一个元素,*默认是object*
        coll.add(123);
        coll.add("aa");
        coll.add(new Date());
        //3. addAll(Collection coll):
        Collection coll1 = Arrays.asList(1,2,3);
        coll.addAll(coll1);
        sout(coll.size());//6
        //查看集合元素
        sout(coll);//Arraylist重写了toString()
        //4. isEmpty(); return boolean
        //5. clear(); 
    }
    
    @Test
    public void testCollection2() {
        Collection coll = new Arraylist();
        coll.add(123);
        coll.add("aa");
        coll.add(new Date());
        coll.add("bb");
        //6. contains(Object obj)
        //判断依据: 根据元素所在类的equals()进行判断, 
        //如果存入集合中的元素是自定义类的对象.要求:自定义类要重写euqals()!
        boolean b1 = coll.comtains(123)
        //7. containsAll(Collection coll)
        Collection coll1 = new Arraylist();
        coll1.add(123);
        coll1.add("AA");
        boolean b3 = coll.containsAll(coll1);
        sout("#" + b3);
    }
}
  • Iterator接口
public class TestIterator {
  @Test
  public void testIterator() {
     		Collection coll = new Arraylist();
        coll.add(123);
        coll.add("aa");
        coll.add(new Date());
    		// 迭代器遍历集合
    		Iterator i = coll.iterator();
    		while(i.hasNext()) {
          sout(i.next());
        }
    		// foreach遍历
    		for(Object o: coll) {
          sout(o);
        }
  }
}
  • List接口(有序, 可重复)

    • List 方法

      image-20200517230137354

    • ArrayList(List的主要实现类)

      • 本质是对象引用的一个可变数组
      • 线程不安全(vector线程安全, 但效率低, 不使用)
    • LinkedList

      • 链表实现
      • 频繁插入/删除时使用
  • Set接口(无序, 不重复)

    • 无序!=随机

      元素的位置根据hash值存储

    • hashcode(), equals(), compareTo()要重写, 保证得到一致的结果

    • HashSet(主要 实现类)

    • LinkedHashSet

      • 使用链表维护添加 的顺序, 但存储是无序
      • 效率: 遍历>HashSet, 插入删除<HashSet
    • TreeSet

      • 元素是同一类
      • 排序
        • 自然
        • 实现Comparable接口的compareTo()
          • String, 包装类已重写. 升序(小 -> 大, a -> z)
        • 定制
          • 实现Comparator接口的compare()

Map接口

Map接口继承树

HashSet是HashMap的一种特殊情况, 底层实现有关联

  • 保存具有单向一对一的数据

    key, value可以是任何引用类型数据

    key常用Set存, 所以不允许重复, 需重写hashCode(), equals()

    value常用String存

  • 方法

  • HashMap(主要 )

    • 子类: LinkedHashMap 迭代顺序与插入顺序一致
  • TreeMap

    类似TreeSet

  • Hashtable

    • 过时, 线程安全. 不允许null作为key, value

    • 子类: Properties

      key, value都为String. 常用于处理属性文件

      Properties pros = new Properties();
      pros.load(new FileInputStream("jdbc.properties"));
      String user = pros.getProperty("user");
      Sout(user);
      

Collections工具类

  • 提供静态方法操作Collection, Map的元素

    • 排序: reverse(List), shuffle(List), sort(List), sort(List,Comparator)

    • 查找, 替换: Object max(Collection), Object max(Collection,Comparator), intfrequency(Collection,Object), void copy(List dest,List src), boolean replaceAll()

    • 同步: synchronizedXxx()

泛型 generics

集合中的泛型

public interface List<E> {
  void add(E x);
  Iterator<E> iterator();
}

自定义泛型类

class person<T> {
  // 定义属性
  private T info;
  // 定义方法
  public T getInfo() {
    return info;
  }
  public void setInfo(T info) {
    this.info = info;
  }
  // 定义构造器
  public Person(T info) {
    this.info = info;
  }
}
  • static 方法不能声明泛型
  • try-catch中不能定义泛型
  • 泛型方法

    [访问权限] <泛型> 返回类型 方法名**([泛型标识 参数名称])** 抛出的异常

    public class DAO {
      public <E> E get(int id, E e) {...}
    }
    

泛型和继承

若B是A的一个子类型(类/接口), G是有泛型声明的类/接口, G<B>不是G<A>子类型

通配符

  • ?, 如 List<?>, Map<?>

  • List<?>List<String>List<Object>等各种泛型List的父类

    • 读取 List<?>中元素是安全的, 因为返回的总是Object
    • 写入 List<?>中元素是不允许的, 除了null, 因为null是所有类型的成员
  • 有限制的通配符

    • <? extends A> 允许泛型为A及A子类的调用
    • <? super A> 允许泛型为A及A父类的调用
    • <? extends Comparable> 允许泛型为实现Comparable接口的实现类的引用调用

枚举 Enum type

  • 枚举类对象的属性不应允许被改动**,** 所以应该使用 private final 修饰

  • enum

    • 必须在枚举类的第一行声明枚举类对象

    • switch-case: case子句直接使用枚举值

    • 主要方法:

      • values() 返回对象数组. 用于遍历所有枚举值
      • valueOf(String str) 把一个字符串转为对应的枚举类对象。要求字符串必须是枚举类对象的“名字”。否则,会有运行异常。
    • 实现接口

      若需要每个枚举值在调用实现的接口方法呈现出不同的行为方式, 则可以让每个枚举值分别来实现该方法

    enum Season implements Info{
      SPRING("1", "A") {
      	public void show() {
          sout("a");
        }
      },
      SUMMER("2", "B") {
        public void show() {
          sout("b");
        }
      },
      FALL("3", "C"),
      WINTER("4", "D");
    }
    interface Info {
      void show();
    }
    

注解 Annotation

  • 内置

    • @Override: 限定重写父类方法, 只能用于方法
    • @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
    • @SuppressWarnings: 抑制编译器警告
  • 自定义

    public @interface MyAnnotation { 
      String str() default "hello";
    }
    
  • 元注解: 修饰其他注解

    Retention
    Target
    Documented
    Inherited

IO

package java.io

File类

File: 文件和目录路径名的抽象表示形式

  • 能新建、删除、重命名文件/目录, 但不能访问文件内容本身。如果需要访问文件内容本身,需使用输入/输出流

  • File对象可以作为参数传递给流的构造函数

  • 方法

    • 访问文件名

      getName()
      getPath()
      getAbsoluteFile()
      getAbsolutePath()
      getParent()
      renameTo(File newName)

    • 文件检测

      exists()

      canWrite()

      canRead()

      isFile()

      isDirectory()

    • 获取文件信息

      lastModified()

      length()

    • 文件操作

      createNewFile()

      delete()

    • 目录操作

      mkDir()

      mkDirs()

      list()

      listFiles()

  • 分类

    • 按操作数据单位 不同分为:字节流(8 bit),字符流(16 bit, 文本)

    • 流向 不同分为:输入流,输出流

    • 角色 的不同分为:节点流(直接处理数据),处理流(加工节点流)

      (抽象基类)字节流字符类
      输入流InputStreamReader
      输出流OutputStreamWriter

      java.io涉及40几个类, 都是从上面4个抽象基类派生的

      派生出的子类名以父类名作为后缀

  • 打开文件IO不属于内存中资源, 无法被自动回收, 应显式关闭IO.

    .close()

节点流

用try-catch处理保证流一定关闭

  • FileInputStream/Reader

    1.建立一个流对象,将已存在的一个文件加载进流。 FileReader fr = new FileReader(“Test.txt”);
    2.创建一个临时存放数据的数组。 char[] ch = new char[1024];
    3.调用流对象的读取方法将流中的数据读入到数组中。 fr.read(ch);

    • int read(byte[] b) int read(char [] c)

    • int read(byte[] b, int offset, int length) int read(char[] b, int offset, int length)

  • FileOutputStream/Writer

    1.创建流对象,建立数据存放文件 FileWriter fw = new FileWriter(“Test.txt”);
    2.调用流对象的写入方法,将数据写入流 fw.write(“text”);
    3.关闭流资源,并将流中的数据清空到文件中 fw.close();

    • void write(byte[] b/char[] cbuf)
    • void write(byte[] b/char[] buff, int offset, int length)
    • void write(String str) void write(String str, int off, int len)

缓冲流

  • 在使用缓冲流类时,会创建一个内部缓冲区数组

  • 缓冲流要“套接”在相应的节点流之上,提高了读写的效率,增加了一些新方法

  • BufferedInputStream/Reader

    • BufferedReader br.readline() 一次读一行
  • BufferedOutputStream/Writer

    • 每次写入后刷新缓冲区 flush()

    20200522-2T89qF

转换流

  • 在字节流和字符流之间 按指定字符集转换
  • 同样要套接在相应节点流上
  • InputStreamReader和OutputStreamWriter

标准输入输出流

  • System.in和System.out分别代表系统标准的输入和输出设备. 默认输入设备是键盘,输出设备是显示器

  • System.in的类型是InputStream System.out的类型是PrintStream, 是OutputStream的子

    类FilterOutputStream的子类

  • 通过System类的setIn(),setOut()对默认设备进行改变

打印流

  • PrintStream(字节打印流)和PrintWriter(字符打印流)

数据流

  • 处理基本数据类型, String, DataInputStream 和 DataOutputStream

对象流

  • ObjectInputStream和OjbectOutputSteam

  • 存储和读取对象的处理流

  • 序列化(Serialize):用ObjectOutputStream类将一个Java对象 写入IO流中
    反序列化(Deserialize):用ObjectInputStream类从IO流中恢复该Java对象
    ObjectOutputStream和ObjectInputStream不能序列化statictransient修饰的成员变量

  • 类及属性都要实现Serializable接口才能序列化

  • 实现Serializable接口的类都有一个表示序列化版本标识符的静态变量: private static final long serialVersionUID

    • 应显示定义.

      如果类没有显示定义这个静态变量,它的值是Java运行时自动生成。若类的源代码作了修改,serialVersionUID可能发生变化

    • 用途: 类的不同版本间的兼容性

RandomAccessFile

跳到文件的任意地方来读、写文件

  • RandomAccessFile对象包含一个记录指针,用以标示当前读, 写处的位置。RandomAccessFile 类对象可以自由移动记录指针:
    long getFilePointer(): 获取文件记录指针的当前位置

    void seek(long pos): 将文件记录指针定位到 pos 位置

  • 构造器
    public RandomAccessFile(String name, String mode)

    • mode 指定 RandomAccessFile 的访问模式:

      r: 以只读方式打开
      rw:打开以便读取和写入
      ➢ **rwd:**打开以便读取和写入;同步文件内容的更新
      ➢ **rws:**打开以便读取和写入;同步文件内容和元数据的更新

多线程

java.lang.Thread类

创建线程第一种方法: 继承Thread类

  1. 定义子类继承Thread类。
  2. 子类中重写Thread类中的run方法。
  3. 创建Thread子类对象,即创建了线程对象。
  4. 调用线程对象start方法:启动线程,调用run方法。

20200523-Zkyuv3

Thread 常用方法

  • void start(): 启动线程,并执行对象的run()方法

  • run(): 线程在被调度时执行的操作

  • String getName(): 返回线程的名称

  • void setName(String name):设置该线程名称

  • static currentThread(): 返回当前线程

  • static void yield(): 暂停当前正在执行的线程,把执行机会让给优先级相同或更高的线程

  • join() :当某个程序执行流中调用其他线程的 join() 方法时, 调用线程将被阻塞,直到 join() 方法加入的 join 线程执行完为止

  • static void sleep(long millis):(指定时间:毫秒) 令当前活动线程在指定时间段内放弃对CPU控制,使其他线程有机会被执行,时间到后重排队。

  • 线程的优先级控制
    MAX_PRIORITY(10); MIN _PRIORITY (1); NORM_PRIORITY (5);

    • 线程创建时继承父线程的优先级

    方法:

    • getPriority() :返回线程优先值
    • setPriority(int newPriority) :改变线程的优先级

java.lang.Runnable接口

创建线程第二种方法: 实现Runnable接口. 更好

  1. 定义子类,实现Runnable接口。
  2. 子类中重写Runnable的run()
  3. 通过Thread类含参构造器创建线程对象
  4. 将Runnable的子类对象作为实际参数传递给Thread类的构造方法中
  5. 调用Thread类的start():开启线程,调用run()
class PrimeRun implements Runnable {
         long minPrime;
         PrimeRun(long minPrime) {
             this.minPrime = minPrime;
         }
         public void run() {. . .}
}

PrimeRun p = new PrimeRun(143);
new Thread(p).start();

线程的生命周期

20200523-KJoiD5

线程的同步

  • 提出的问题:

    多个线程操作共享数据可能出现一个线程未执行完毕时, 另外的线程参与进来而破坏数据。

  • 解决办法**😗*

    对多条操作共享数据的语句,只能让一个线程都执行完,在执行过程中, 其他线程不可以参与执行。

    • 同步代码块

      所有线程必须共用同一把锁; 包裹的代码块不多也不少, 只有共享数据的部分

      // 可以用任意一个类的对象充当同步监视器(锁)
      Object obj = new Object();
      public void run() {
        // Object obj = new Object(); 这样会导致每个线程自己有一把锁, 没有同步的作用
        synchronized(obj) {
        // 需要被同步的代码
      	}
      }
      
    • 同步方法

      同步方法(非静态的)的锁为this。
      同步方法(静态的)的锁为当前类本身。

      public synchronized void show (String name){...}
      

    互斥锁 mutex

    防止两条线程同时对同一公共资源进行读写的机制

    • 释放锁:

      • 当前线程的同步方法/代码块执行结束; 被break, return终止; 异常抛出
      • 当前线程的同步方法/代码块执行wait(), 暂停当前线程, 并释放锁
    • 不会释放锁:

      • 遇到sleep(), yield()暂停当前线程
    • 死锁

      不同的线程分别占用对方需要的同步资源不放弃,都在等待对方放弃自己需要的同步资源,就形成了线程的死锁.

      减少同步资源的定义.

线程通信

java.lang.Object

  • wait() 令当前线程挂起并放弃CPU、同步资源,使别的线程可访问并修改共享资源,而当前线程排队等候再次对资源的访问
  • notify():唤醒正在排队等待同步资源的线程中优先级最高者
  • notifyAll():唤醒正在排队等待资源的所有线程

这三个方法只有在synchronized方法或代码块中使用,否则会报 java.lang.IllegalMonitorStateException异常

常用类

String类

  • 使用Unicode字符编码,一个字符占两个字节
  • String是一个final类,代表不可变的字符序列. 底层实现是char[]

20200525-tVoKkl

常量池理解

  • 字符串对象操作

    • public int length()
    • public char charAt(int index)
    • public boolean equals(Object anObject)
    • public int compareTo(String anotherString)
    • public int indexOf(String s)
    • public int indexOf(String s ,int startpoint)
    • public int lastIndexOf(String s)
    • public int lastIndexOf(String s ,int startpoint)
    • public boolean startsWith(String prefix)
    • public boolean endsWith(String suffix)
    • public boolean regionMatches(int toffset, String other, int ooffset, int len)
  • 字符串对象修改

    • public String substring(int startpoint)

    • public String substring(int start,int end)

    • pubic String replace(char oldChar,char newChar)

    • public String replaceAll(String old,String new)

    • public String trim()

    • public String concat(String str)

    • public String[] split(String regex)

  • 包装类, 基本数据类型, 字节/字符数组 相互转换

    1. 字符串 与 基本数据类型, 包装类 转换

      • 字符串 -> 基本数据类型/包装类: 包装类的parseXxx(String str)
      • 基本数据类型/包装类 -> 字符串: 字符串重载的valueOf()
    2. 字符串 与 字节数组 转换

      • 字符串 -> 字节数组: 字符串的getBytes()

      • 字节数组 -> 字符串: 字符串的构造器

    3. 字符串 与 字符数组 转换

      • 字符串 -> 字符数组: 字符串的toCharArray()
      • 字符数组 -> 字符串: 字符串的构造器

StringBuffer

java.lang.StringBuffer代表可变的字符序列,可以对字符串内容进行增删改查. 线程安全.

添加 append()

删除 delete(int start, int end)

修改 setCharAt(int index, char ch)

插入 insert()

反转 reverse()

长度 length()

StringBuilder

java.lang.StringBuilder和StringBuilder类似, 效率更高, 但线程不安全

日期类

  • java.lang.System类下的public static long currentTimeMillis(), 用于计算时间差

  • java.util.Date (及其子类 java.sql.Date)

    • toString()
    • getTime()
  • java.text.SimpleDateFormat

    不与语言环境有关的方式来格式化和解析日期的具体类.

    格式化(日期->文本)、解析(文本->日期)

  • java.util.Calendar

    抽象基类,主用用于完成日期字段之间相互操作的功能

    • 获取Calendar实例的方法

      • 使用Calendar.getInstance()方法
      • 调用它的子类GregorianCalendar的构造器
    • get(), add(), Date getTime()/setTime(Date d)

Math类

java.lang.Math提供了一系列静态方法用于科学计算;其方法的参数和返回值类型一般为double型

BigInteger/BigDecimal

支持任意精度

反射

**Reflection(反射)**是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息且能直接操作.

Class类

  • java.lang.Class 本身是一个类
  • 一个类在JVM中只有一个Class对象, 因为只能创建一次
  • 一个Class对象对应一个加载到JVM的一个.class文件
  • 通过Class可以完整得到一个类的结构

获取Class类的对象

  1. 若已知具体的类,通过类的class属性获取,该方法最安全可靠,性能最高

    Class clazz = String.class;
    
  2. 已知某个类的实例,调用该实例的getClass()方法获取Class对象

    Class clazz = “hello, world”.getClass(); 
    
  3. 已知一个类的全类名,且该类在类路径下,可通过 Class类的静态方法forName() 获取,可能抛ClassNotFoundException

    Class clazz = Class.forName(“java.lang.String”);
    
  4. 类的加载器(了解)

    ClassLoader cl = this.getClass().getClassLoader(); 
    Class clazz4 = cl.loadClass(“类的全类名”);
    

    getResourceAsStream(String str):获取类路径下的指定文件的输入流

创建类对象并获取其完整结构

  • 创建类的对象

    1. 调用Class对象的newInstance()
      • 类必须要有一个无参的构造器
      • 类的构造器访问权限足够
    2. 若类没有无参构造器, 则先取得指定形参的构造器, 显式调用, 再实例化
  • 获取对应的运行时类的属性

    • Field[] getFields() 获取类中及其父类中声明为public的属性
    • Field[] getDeclaredFields() 获取类本身声明的所有属性
      • int getModifiers() 以整数形式返回此Field的修饰符
      • Class<?> getType() 得到属性类型
      • String getName() 返回属性名
  • 获取对应的运行时类的方法

    • Method[] getMethods() 返回类或接口本身的public的方法
    • Method[] getDeclaredMethods() 返回类及父类的全部方法
      • Class<?> getReturnType()取得全部的返回值
      • Class<?>[] getParameterTypes() 取得全部的参数
      • int getModifiers()取得修饰符
      • Class<?>[] getExceptionTypes() 取得异常信息
  • 构造器

    • public Constructor<T>[] getConstructors()
      返回类的所有public构造方法
    • public Constructor<T>[] getDeclaredConstructors()
      返回此类声明的所有构造方法。
      • 取得修饰符: public int getModifiers()
      • 取得方法名称: public String getName()
      • 取得参数的类型: public Class<?>[] getParameterTypes()
  • 注解

    getAnnotation(Class<T> annotationClass)
    getDeclaredAnnotations()

  • 泛型

    • 获取父类泛型类型:Type getGenericSuperclass()
    • 泛型类型: ParameterizedType
    • 获取实际的泛型类型参数数组: getActualTypeArguments()
  • Package getPackage()

调用指定属性, 方法, 构造器

  • 属性

    • public Field getField(String name) 返回public的属性名为name的属性。
      public Field getDeclaredField(String name) 返回属性名为name的属性。

    • public Object get(Object obj) 取得指定对象obj上此Field的属性内容
      public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内

      当类中属性设置为private,在使用set()和get()方法时,首先要使用Field类中的setAccessible(true)方法将需要操作的属性设置为可以被外部访问

  • 方法

    1. 通过Class类的getMethod(String name,Class...parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。

    2. 调用Class.newInstance()

    3. 若原方法声明为private,则需要在调用invoke()方法前, 显式调用方法对象setAccessible(true)方法,将可访问 private的方法。

    4. 之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。

动态代理

  • 代理模式: 使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象

  • 动态代理步骤

    1. 创建被代理的类, 接口
    2. 创建一个实现接口InvocationHandler的类,必须实现invoke方法,以完成代理的具体操
    3. 通过Proxy类的静态方法Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个代理类对象
    4. 当通过代理类对象发起对被重写的方法调用时, 会转换为invoke()调用
  • AOP (Aspect Orient Programming)

    20200528-9cyVe4

    20200528-qk349Y

网络编程

网络基础

  • 如何实现网络中主机互相通信

    • 通信双方地址

    • 数据传输的规则: OSI模型, TCP/IP协议

      20200528-ACK9ib

  • IP, 端口号

    • IP

      • 域名-(DNS)->IP

      • java.net.InetAddress类

        没有公共构造器, 提供2个静态方法获取实例:

        getByName(String host)

        getByAddress(byte[] addr)

    • 端口号: 进程

      16位整数 0-65535. 其中0-1023被预先定义占用.

  • 网络通信协议

    • TCP(Transmission Control Protocol)
      使用TCP协议前,须先采用“三次握手”方式建立连接
      在连接中可进行大数据量的传输
      传输完毕,需释放已建立的连接,“四次挥手”

      可靠但效率低

    • UDP(User Datagram Protocol)

      将数据、源、目的封装成数据包,不需要建立连接

      每个数据报的大小限制在64K内

      因无需连接,故是不可靠的

      发送数据结束时无需释放资源,速度快

  • Socket 套接字

    • 通信的两端都要有Socket,是两台机器间通信的端点
    • Socket允许程序把网络连接当成一个流,数据在两个Socket间通过IO传输。
    • 一般主动发起通信的应用程序是客户端,等待通信请求的为服务端

    当server使用阻塞IO(如InputStream.read()), 在数据没有到达前,read 会挂起,进程会卡住. 需要client在发送完数据后, 显式告诉server发送完毕(void shutdownOutput())

  • UDP通信

    1. DatagramSocket与DatagramPacket

      UDP数据报通过数据报套接字DatagramSocket发送和接收,

      DatagramPacket对象封装了UDP数据报,在数据报中包含了发送端的IP地址和端口号以及接收端的IP地址和端口号

    2. 建立发送端,接收端

    3. 建立数据包

    4. 调用Socket的发送、接收方法

    5. 关闭Socket

  • URL编程

    java.net.URL类

    • URL的方法 InputStream openStream():能从网络上读取数据
    • URLConnection: 要发送数据, 则先建立连接. 通过URLConnection openConnection()生成URLConnection对象
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值