乐趣区

关于学习笔记:Java

开发环境

  1. JDK:JAVA 编译环境
  2. JRE:JAVA 运行环境

根本语法

数据类型(四种八类型)

  1. 整数型:byte, short, int, long;
  2. 浮点型:float, double;
  3. 字符型:char;
  4. 布尔型:boolean.

书写标准

类名放弃首字母大写,包名放弃小写,办法名应用驼峰写法。

面向对象

在 JAVA 中,万事万物都是对象 。尽管如此,理论的代码编译中操作的的确对象的 援用(reference)

类也是对象

对象援用是绝对于对象独立的存在,也就是说 有一个对象利用,然而不须要一个对象与之对应

Car carKey;

以上创立的只是援用,而并非对象。如果想在代码之中应用这个援用时,会返回一个没有对象关联的异样。平安的做法是,在创建对象援用时把一个对象赋给它。此时咱们须要应用 new 办法。

new 一个对象

应用 new 进行对象的创立:

Sheep sheep1 = new Sheep();
Sheep sheep2 = new Sheep("codesheep", 18, 65.0f);

通过 new 办法,通过调用类的无参或有参结构的办法来实例化了两个对象。

在创建对象的过程中,JVM解决了如下步骤

  1. 首先,new一个对象时,以 Sheep sheep = new Sheep() 为例,JVM会先来查看 Sheep 这个符号援用的类是否曾经被加载过,如果没有就要执行对应类的加载过程。在这个过程中,对象占用的内存就曾经定下来了。
  2. 申明类型援用。Sheep sheep = new Sheep()中就申明了一个 Sheep 类型的援用sheep
  3. 依照第一步中布局的内存调配打算,JVM会在堆上给对象分配内存。
  4. 初始化 0 值。例 int 的初始化 0 值就是 0,对象化的初始化 0 值就是 null。
  5. 接下来 JVM 会进行对象头的设置,这外面就次要包含对象的运行时数据(比方 Hash 码、分代年龄、锁状态标记、锁指针、偏差线程 ID、偏差工夫戳等)以及类型指针(JVM 通过该类型指针来确定该对象是哪个类的实例);
  6. 属性的显示初始化也好了解,比方定义一个类的时候,针对某个属性字段手动的赋值,如:private String name = "codesheep"; 就在这时候给初始化上;
  7. 最初是调用类的构造方法来进行进行构造方法内形容的初始化动作。

通过以上的步骤一个对象才得以诞生。

属性和办法

类的一个最根本的因素就是属性和办法。

属性 也被称为字段,是类的重要组成部分。属性能够使任意类型的对象,也能够是最根本的数据类型。

class A{
    int a;
    Apple apple;
}

类中还应该包含 办法,办法示意的是做某些事件的形式。办法其实就是函数,只不过 Java 习惯把函数成为办法,这种叫法也体现了面向对象的概念。

办法 的根本形成包含:

  1. 办法名称;
  2. 参数;
  3. 返回值;
  4. 办法体。

e.g.

public int getResult(){
    // ...
    return 1;
}

其中 getResult 就是办法名,()示意承受的参数,return示意办法的返回值,{}中的为办法体。

构造方法

在 Java 中,有一种非凡的办法被称为 构造方法 (或构造函数、结构器)。在 Java 中,通过提供这个结构器,来确保每个对象都被 初始化 。构造方法只能在对象 创立期间 调用 一次 ,保障了对象初始化的进行。构造方法比拟非凡,它 没有参数类型和返回值,它的名称要和类名称保持一致,并且构造方法能够有多个。

e.g.

// 一堆初始化办法的初始化类
class Apple{
    int sum;
    String color;
    
    public Apple(){}
    public Apple(int sum){}
    public Apple(String color){}
    public Apple(int sum, String color){}}

// 开始
class createApple{public static void main(String[] args){Apple apple1 = new Apple();
        Apple apple2 = new Apple(1);
        Apple apple3 = new Apple("red");
        Apple apple4 = new Apple(2,"color");
    }
}

以上,在 Apple 类中,定义了四个构造方法。其中,不加任何参数的构造方法被称为默认的构造方法,即:

Apple apple1 = new Apple();

如果类中没有定义任何构造方法,JVM 会主动生成一个默认的构造方法。默认的构造方法以被称为默认结构器或者无参结构器。然而如果定义了任何一个构造方法,JVM 将不再提供默认结构器。

办法重载

在 Java 中一个很重要的概念是办法的重载,它是类名的不同表现形式。之前说的构造函数,实际上也是重载的一种。

每个重载的办法都有举世无双的参数列表(其中包含参数的类型,程序,参数数量等),此为 Java 来辨别重载指标办法的规范。

重载的条件

  1. 办法名称必须雷同;
  2. 参数列表必须不同(个数不同、类型不同、参数类型排列程序不同等);
  3. 办法的返回类型能够雷同也能够不同;
  4. 仅仅返回类型不同不足以成为办法的重载;
  5. 重载是产生在编译时的,因为编译器能够依据参数的类型来抉择应用哪个办法。
public class Apple{
    int sum;
    String color;
    
    public Apple(){}
    public Apple(int sum){}        // 重载
    
    public int getApple(int num){return 1;}
    
    // 重载
    public String getApple(String color){return "color";}
}

办法的重写

办法重写尽管与重载名字很类似,然而齐全不同。办法重写的形容是对 子类和父类 之间的。而重载指的是 同一类 中。

重写的准则:

  1. 重写的办法必须要和父类保持一致,包含 返回值的类型,办法名,参数列表 也都一样;
  2. 重写的办法能够应用 @Override 注解来进行标注;
  3. 子类中重写办法的拜访权限不能低于父类中办法的拜访权限。
class Fruit{public void eat(){System.out.println('eat fruit');
    }
}

class Apple extends Fruit{
    
    @Override
    public void eat(){System.out.println('eat apple');
    }
}

初始化

类初始化

创建对象援用时,如果没有相应的类,则实际上是调用了这个对象的无参构造方法来进行的初始化,如下:

class Car{public Car(){}}

实际上就是初始化了一个类,默认进行,由 JVM 主动增加。

成员的初始化

Java 会尽量保障每个变量在应用前都会取得初始化,初始化波及两种初始化。

  1. 一种是编译器默认指定的字段初始化,根本数据类型的初始化。

    | 类型 | 初始值 |
    | :—–: | :——: |
    | boolean | false |
    | char | /u0000 |
    | byte | (byte)0 |
    | short | (short)0 |
    | int | 0 |
    | long | 0L |
    | float | 0.0f |
    | double | 0.0d |

    其余对象类型的初始化,String 也是一种对象,对象的初始值都是 null,其中也包含根本类型的包装类。

  2. 一种是指定数值的初始化,e.g.

    int a = 11

    也就是说,指定 a 的初始化值不是 0,而是 11. 其余根本类型和对象类型也是一样的。

结构器初始化

能够利用结构器来对某些办法和某些动作进行初始化,确定初始值,e.g.

public class Counter{
    int i;
    public Counter(){i = 11;            // 结构器对 i 的初始化值解决,对 i 初始化为 11.}
}

初始化程序

须要探讨的初始化程序:

  • 动态属性:static 结尾定义的属性;
  • 静态方法块:static{}
  • 一般属性:非 static 定义的属性;
  • 一般办法块:{}包起来的代码块;
  • 构造函数:类名雷同的办法;
  • 办法:一般办法。
public class LifeCycle{
    // 动态属性
    private static String staticField = getStaticField();
    // 静态方法块
    static {System.out.println(staticField);
        System.out.println("静态方法块初始化");
    }
    // 一般属性
    private String field = getField();
    // 一般办法块
    {System.out.println(field);
    }
    // 构造函数
    public LifeCycle(){System.out.println("构造函数初始化");
    }
    
    public static String getStaticField(){
        String statiFiled = "Static Field Intial";
        return statiFiled;
    }
    
    public static String getField(){
        String filed = "Field Initial";
        return filed;
    }
    // 主函数
    public static void main(String[] args){new LifeCycle();
    }
}

执行程序:

  1. 动态属性初始化;
  2. 静态方法块初始化;
  3. 一般属性初始化;
  4. 一般办法块初始化;
  5. 构造函数初始化。

数组初始化

数组是雷同类型的、用一个标识符名称风撞到一起的一个对象序列或根本类型数据序列。数组是通过方括号下表操作符 [] 来定义应用的。e.g.

// 以下两段含意雷同
int[] a1;
int a1[];

// 赋值操作
int arrary[4] = {1, 2, 3, 4};        // 间接给每个元素赋值
int arrary[4] = {1, 2};        // 给一部分赋值,前面的都是 0
int arrary[] = {1,2};        // 由参数的各述决定数组的个数

可变参数列表

Java 中对数组的一种比拟冷门的用法就是 可变参数,可变参数的定义如下:

public int add(int... numbers){
    int sum = 0;
    for(int num : numbers){sum += num;}
    return sum;
}

而后,能够应用以下办法进行可变参数的调用:

add();        // 不传参数
add(1);        // 传递一个参数
add(2,1);        // 传递多个参数
add(new Integer[] {1, 3, 2});        // 传递数组

对象销毁

Java 与 C 语言不同的一个重要特色就是 Java 不须要本人手动治理对象的销毁工作,而是由 JVM来治理和销毁。尽管不须要手动销毁,然而仍须要晓得 对象作用域 这个概念。

对象作用域

绝大多数语言都有 作用域 (scope) 这个概念。作用域决定了其外部定义的变量名的可见性和生命周期。在 Java 中,作用域通常由 {} 的地位来决定,e.g.

{
    int a = 11;
    {int b =12;}
}

a 变量会在两个 {} 作用域无效,而 b 变量的值只能在它本人的 {} 内无效。

尽管存在作用域,然而不容许以下写法:

{
    int x = 11;
    {int x = 12;}
}

这种写法在 C 中是能够的,然而在 Java 中不容许,因为老头认为这样写会导致程序凌乱。

this 和 super

this super 都是 Java 中的关键字

this 标识的以后对象,this 能够调用办法、调用属性和指向对象自身。this 在 Java 中的应用个别有三种。

e.g.

public class Apple{
    
    int i = 0;
    
    Apple eatApple(){
        i++;
        return this;            // 退出 this,调用 eatApple()总会返回对象本身}
    
    public static void main(String[] args){Apple apple = new Apple();
        apple.eatApple().eatApple();
    }
}

//this 润饰属性
public class Banana{
    private int num;
    
    public Banana(int num){this.num = num;}
    
    public static void main(String[] args){new Banana(10);        // 传递 "10" 给全局变量 num
    }
}

//this 充当全局关键字,this()必须放在构造方法的第一行,否则编译不通过
public class Apple{
    private int num;
    private String color;
    
    public Apple(int num){this(num,"红色");        
    }
    
    public Apple(String color){this(1,color);
    }
    
    public Apple(int num, String color){
        this.num = num;
        this.color = color;
    }
}

如果 this 是指向本身的一个援用,那么 super 就是指向父类的一个援用。super 关键字和 this 一样,能够应用 super.object 来援用父类成员。

e.g.

public class Fruit{
    int num;
    String color;
    
    public class Apple extends Fruit{
        
        @Override
        public void eat(){
            super.num = 10;
            System.out.println("eat" + num + "Apples");
        }
    }
}

应用 super 来调用父类的构造函数同this

两个办法都有的特色:

  1. 调用地位都是构造函数第一行,非构造函数地位自定;
  2. 调用次数:一个构造函数只可调用一次。

访问控制权限

访问控制权限又称为 封装 ,它是面向对象三大特色中的一种。访问控制类的外围是 只对须要的类可见

Java 中成员的拜访权限总共有四种:public, protected, default, private.

private default protected public
同一类
同一包中的类
子类
其余包中的类

标识能够拜访。

继承

继承是所有 oop 语言都不可短少的一部分。只有一个类被创立,那么它就隐式继承自 Object 父类,只不过没有指定。如果你显示指定了父类,那么你继承于父类,而你的父类继承于 object 类。

// 继承关键字:extends
class Father{}

class Son extends Father{}

Son类会保留有 Father 的属性,如果 Son 类没有实现本人的办法的话,那么默认就是用的父类 Father 的办法。如果子类实现了本人的 feature 办法,那么就相当于是重写了父类的 feature 办法。

多态

多态指的是 同一个行为具备不同的表现形式。是指一个类实例(object)的雷同办法在不同情景下具备不同表现形式。封装和继承是多态的根底,也就是说多态只是一种表现形式而已。

多态实现的三个充要条件

  1. 继承
  2. 重写父类办法
  3. 父类援用指向子类对象

e.g.

public class Fruit{
    int num;
    
    public void eat(){System.out.println("eat Fruit");
    }
}

public class Apple extends Fruit{
    
    @Override
    public void eat(){
        super.num = 10;
        System.out.println("eat" + num + "Apple");
    }
    
    public static void main(String[] args){Fruit fruit = new Apple();
        fruit.eat();}
}

如代码所示,Fruit fruit = new Apple() Fruit 类型的对象指向了 Apple 对象的援用,此处便是父类援用指向子类对象,因为 Apple 继承于 Fruit,并且重写了 eat 办法,所以可能体现出多种状态的模式。

组合

指:将对相援用置于新类中。组合也是进步类复用性的一种办法。如果想让类具备更多的拓展性能,要做到 多用组合,少用继承

public class SoccerPlayer{
    
    private String name;
    private Soccer Soccer;
}

public class Soccer{private String soccerName;}

如上 SoccerPlayer 中援用了 Soccer 类,通过援用 Soccer 类,调用其中的属性和办法。组合和继承石油区别的,如下:

特色 组合 继承
关系 组合是一种 has – a 的关系,能够了解为有一个 集成式一种 is – a 的关系,能够了解为是一个
耦合性 组合的单方是一种松耦合的关系 继承单方紧耦合
是否存在多态 组合不具备多态和向上转型 继承是多态的根底,能够实现向上转型
期间 组合是运行期绑定 继承是编译期绑定

代理

大抵形容:A 想要调用 B 类的办法,A 不间接调用,A 会在本人的类中创立一个 B 对象的代理,再由代理调用 B 的办法。

e.g.

public class Destination {public void todo(){System.out.println("control...");
    }
    
    public class Device{
        
        private String name;
        private Destination desitination;
        private DeviceController deviceController;

        public void control(Destination destination){destination.todo();
        } 
    }
    
    public class DeviceController{
        
        private Device name;
        private Destination destination;
        
        public void control(Destination destination){destination.todo();
        }
    }
}

向上转型

向上转型代表了父类和子类之间的关系,其实父类和自磊之间不仅仅有向上转型,还有向下转型,他们的转型后范畴不同。

  • 向上转型:通过子类对象(小范畴)转化为父类对象(大范畴),这种转换是主动实现的,不必强制。
  • 向下转型:通过父类对象(大范畴)转化为子类对象(小范畴),这种转换不是主动实现的,须要强制指定。

static

static 是 Java 中的关键字,它的意思是 动态的,static 能够用来润饰成员变量和办法,static 用在没有创建对象的状况下调用 办法 / 变量。

  • 用 static 申明的成员变量为动态策动可能员变量,也就是类变量。类变量的生命周期和类雷同,在整个应用程序执行期间都无效。

    static String name = "aaa";
  • 应用 static 润饰的办法称为静态方法,静态方法可能间接实用 类名. 办法名 进行调用。因为静态方法不依赖于任何对象就能够间接拜访,因而对于静态方法来说,是没有 this 关键字的,实例变量都会有 this 关键字的成果。在静态方法中不能拜访类的非动态成员变量和非静态方法。

    static void printMessage(){System.out.println("aaa is aaa");
    }

static 除了润饰副属性和办法外,还有动态代码块的性能,可用于类的初始化操作。进而晋升程序的性能。

public class StaicBlock{
    static{System.out.println("I am sb");
    }
}

因为动态代码块随着类的加载而执行,所以很多时候只须要进行一次初始化操作放在 static 代码块中进行。

final

  • final 润饰类时,示意这个类不能被继承,final 类中的成员变量能够依据须要设为 final,然而要留神 final 类中的所有成员办法都被隐式地指定为 final 办法。
  • final 修式办法时,表明这个办法不能被任何子类重写,因而,如果只有在想明确禁止该办法在子类中被笼罩的状况下能力将办法设置为 final。
  • final 润饰变量分为两种状况,一种是润饰根本数据类型,示意数据类型的值不能被批改;一种是润饰援用类型,示意对其初始化之后便不能再让其指向另一个对象。

接口和抽象类

接口

技术黑箱与统一标准。

在 Java 中,接口是由 interface关键字来示意的,比方咱们能够向上面定义一个接口

public interface 123(){void writeWell();
}

接口的特色:

  • interface接口是一个齐全形象的类,不会提供任何办法的实现,只是会进行办法的定义。
  • 接口中只能是用来那个中拜访修饰符,一种是 public,它对整个我的项目可见;一种是default 缺省值,它只具备包拜访权限。
  • 接口只提供办法的定义,接口没有实现,然而接口能够被其余类实现。也就是说,实现接口的类须要提供办法的实现,实现接口应用 implements 关键字来显示,一个接口能够有多个实现。
class 123 implements 123Job{
    
    @Override
    public void writeWell(){Sysyem.out.println("123");
    }
}
  • 接口不能被实例化,所以接口中不能有任何构造方法,定义构造方法编译会出错。
  • 接口的实现比方实现接口的全副办法,否则必须定义为抽象类。

抽象类

抽象类是一种形象能力弱于接口的类,在 Java 中,抽象类应用 abstract 关键字来示意。如果把接口形容为为狗这个动物,那么抽象类能够说是毛色是红色、小型的种类,而实现类能够是具体的类,比如说是泰迪,博美。能够如下图定义抽象类

public interface Dog {void FurColor();
    
}

abstract class WhiteDog implements Dog {public void Fur Color(){System.out.println("Fur is white.");
    }
    abstract void SmallBody();}

在抽象类中,具备如下特色

  • 如果一个类中有形象办法,那么这个类肯定是抽象类。应用关键字 abstract 润饰的办法肯定是形象办法,具备形象办法的类肯定是抽象类。实现类办法中只有办法具体的实现。
  • 抽象类中不肯定只有充想办法,抽象类中也能够有具体的办法。能够抉择是否实现这些办法。
  • 抽象类中的束缚不想接口那么严格,能够在抽象类中定义 构造方法、形象办法、一般属性、办法、动态属性、和静态方法
  • 抽象类和接口一样不能被实例化,实例化只能实例化 具体的类

异样!

异样是程序常常会呈现的,发现错误的最佳时机切实编译阶段,也就是在试图运行程序之前。然而在编译期间并不能找到所有的谬误,有一些 NullPointerExceptionClassNotFoundException异样在编译期间是找不到的,这些异样是 RuntimeExcption 运行时异样,这些异样往往在运行时能力被发现。

咱们写 Java 程序常常会呈现两种问题,一种是 java.lang.Exception,一种是 java.lang.Error,都用来示意出现异常状况,上面针对这两种概念进行了解。

意识 Exception

Exception位于 java.lang 包下,它是一种顶级接口,继承于 Throwable 类,Exception 类及其子类都是 Throwable 的组成条件,是程序呈现的正当状况。

在意识 Exception 之前,有必要先理解一下什么是 Throwable

什么是 Throwable

Throwable 类是 Java 语言中所有 errorsexceptions的父类。只有继承于 Throwable 的类活着其子类才可能被抛出,还有一种形式是带有 Java 中的 @throw 注解也能够抛出。

java 标准 中,对非受查一场合受查异样的定义是这样的

The unchecked exception classes are the run-time exception classes and the error classes.

The checked exception classes are all exception classes other than the unchecked exception classes. That is, the checked exception classes are Throwable and all its subclasses other than RuntimeException and its subclasses and Error and its subclasses.

也就是说,除了 RuntimeException 和其子类,以及 Error 和其子类,其余所有异样都是checkedException

那么依照这种逻辑,咱们能够对 Throwable 及其子类进行演绎剖析。

由此可见,Throwable 位于异样和谬误的最顶层,咱们查看 Throwable 类中发现它的办法和属性有很多,当初只总结其中比拟罕用的几个:

// 返回抛出异样的详细信息
public String getMesage();
public String getLocalizedMessage();

// 返回异样产生的简要形容
public String toString();

// 打印异样到规范输入流上
public void printStackTrace();
public void printStackTrace(PrintStream s);
public void printStackTrace(PrintWriter s);

// 记录栈帧的以后状态
public synchronized Throwable fillInStackTrace();

此外,因为 Throwable 的父类也是 Object,所以罕用的办法还有继承父类的 getClass()getName()办法。

常见的 Exception

当初晓得 Exception 的父类是 Throwable,并且Exception 有两种异样,一种是 RuntimeException;一种是CheckedException,这两种异样都应该去 捕捉

上面列出一些 Java 中常见的异样及其分类。

RuntimeException

序号 异样名称 异样形容
1 ArrayIndexOutOfBoundsException 数组越界异样
2 NullPointerException 空指针异样
3 IllegalArgumentException 非法参数异样
4 NegativeArraySizeException 数组长度为负
5 IllegalStateException 非法状态
6 ClassCastException 类型转换异样

UncheckedException

序号 异样名称 异样形容
1 NoSuchFieldException 示意该类没有指定名称
2 NoSuchMethodException 示意该类没有指定办法
3 IllegalAccessException 不容许拜访某个类
4 ClassNotFoundException 类没有找到

与 Exception 无关的 Java 关键字

Java 中会怎么解决这些异样?有如下关键字:throws, throw, try, finally, catch

throws 和 throw

Java 中异样也是一个对象。若要被自定义抛出或者应用程序抛出,必须借助 throwsthrow语句来定义异样。

throws 与 throw 通常是成对呈现的,如

static void catchException() throws Exception{throw new Exception();
    
}

throw 语句用在办法体外部,表述抛出异样,由办法体内的语句解决。throws 语句用在办法申明后,示意再抛出异样,由该办法的调用者来解决。

throws 次要是申明这个办法会抛出这个类型的异样,使它的使用者晓得要捕捉这个异样。throw 是具体向外抛异样的动作,所以它是抛出一个异样实例。

try finally catch

这三个关键字次要由一下组合:

try...catch

try...finally

try...catch...finally

//try...catch 示意对某一段代码可能抛出异样进行的捕捉
static void cacheException() throws Exception{
    
    try {System.out.println("1");
    }catch (Exception e){e.printStackTrace();
    }
}

//try...finally 示意对一段代码不论执行状况如何,都会走到 finally 中的代码
static void cacheException() throws Exception{for (int i=0, i<5, i++){System.out.println("enter: i=" + i);
        try{System.out.println("execute: i=" + i);
            continue;
        }finally{System.out.println("leave: i =" + i);
        }
    }
}

Error

Error 是程序无奈解决的谬误,示意运行应用程序中较重大问题。大多数谬误与代码编写者执行的操作无关,而示意代码运行时 JVM 呈现的问题。这些谬误大多数是不可查看的,因为它们在应用程序的管制和解决能力之外,而且绝大多数是程序运行时不容许呈现的状况。e.g. OutOfMeoryErrorStackOverFlowError 异样的呈现会有基种状况。

外部类

以上的所有都是一般类的定义。而外部类与其不同。

外部类的定义:能够将一个类的定义放在另一个类的外部,这就是外部类。

创立外部类

public class OuterClass{
    private String name;
    private int age;
    
    class InnerClass{public InnerClass(){
            name = "abc";
            age = 15;
        }
    }
}

在这段代码中,InnerClass 就是 OuterClass 的一个外部类。每个外部类都能独立地继承一个(接口的)实现,所以无论外部类是否曾经继承了某个(接口的)实现,对于外部类都没有影像。外部类领有外部类的拜访权

外部类不仅仅可能定义在类的外部,还能够定义在办法和作用域外部,这种被称为 部分外部类 ,除此之外,还有匿名外部类、外部类以及实现 Java 中的 多重继承。上面是定义外部类的办法:

  • 一个在办法中定义的类(部分外部类)
  • 一个定义在作用域中的类,这个作用域在办法的外部(成员外部类)
  • 一个实现了接口的匿名类(匿名外部类)
  • 一个匿名类,它拓展了非默认结构器的类
  • 一个匿名类,执行字段初始化操作
  • 一个匿名类,它通过实例初始化实现结构

因为每个类都会产生一个 .class 文件,其中蕴含了如何创立该类型的对象的全副信息。应用 $ 来示意外部类的信息,比方OuterClass$InnerClass.class

汇合

Iterable 接口

实现此接口容许对象称为 for-each 循环的指标,也就是加强 for 循环,也是 Java 中的一种 语法糖

List<Object> list = new ArrayList();
for (Object obj: list){}

除了实现此接口的对象外,数组也能够用 for-each 循环遍历,如下:

Object[] list = new Object[10];
for (Object obj: list){}

其余遍历形式

jdk 1.8 之前 Iterator 只有 iterator 一个办法,就是

Iterator<T> iterator();

实现此接口的办法可能创立一个轻量级的迭代器,用于平安地遍历元素,移除元素,增加元素。这外面波及一个 fail-fast 机制。

也能够应用迭代器的办法进行遍历:

for(Iterator it = coll.iterator(); it.hasNext();){System.out.println(it.next());
}

顶级接口

Collection是一个顶级接口,它次要用来定义汇合的约定。

List接口是一个顶级接口,它继承了 Collection 接口,同时也是 ArrayListLinkedList 等汇合元素的父类。

Set接口位于与 List 接口同级的档次上,它同时也继承了 Collection 接口。Set扣扣提供了额定的规定。它对 add,equals,hashCode 办法提供了额定的规范。

Queue适宜 List,Set 接口并列的 Collection 的三大接口之一。Queue的设计用来在解决之前放弃元素的拜访秩序。除了 Collection 根底的操作之外,队列提供了额定的插入,读取,查看操作。

SortedSet接口间接继承于 Set 接口,应用 Comparable 对元素进行天然排序或者应用 Comparator 在创立时对元素提供定制的排序规定。set的迭代器将按升序元素程序遍历汇合。

Map是一个反对 key-value 存储的对象,Map不能蕴含反复的 key,每一个key 最多映射一个 value。这个接口代表了Dictionary 类。Dictionary类是一个抽象类而不是接口。

ArraryList

ArraryList是实现了 List 接口的 可扩容数组(动静数组),它的外部是给予数组实现的。它的具体定义如下:

public class ArraryList<E> extends AbstractList<E> implements List<E>,
RandomAccess, Cloneable, java.io.Serializable {...}
  • ArraryList能够实现所有可抉择的列表操作,容许所有的元素,包含空值。ArraryList还提供了外部存储 list 的办法,它可能齐全代替 Vector,只有一点例外,ArraryList 不是线程平安的容器。
  • ArraryList有一个容量的概念,这个数组的容量就是 List 用来存储元素的容量。
  • ArraryList不是线程平安的容器,如果多个线程中至多有两个线程批改了 ArraryList 的构造的话就会导致线程平安问题,作为代替条件能够应用线程平安的List,应应用Collections.synchronizedList

    List list = Collections.synchronizedList(new ArraryList(...))
  • ArraryList具备 fail-fast 疾速失败机制,可能对 ArraryList 作出失败检测。当在跌待汇合的过程中该汇合在结构上产生扭转的时候,就有可能会产生 fail-fast,即抛出ConcurrentModificationException 异样。

Vector

VectorArraryList 一样,都是基于数组来实现的,只不过 Vector 是一个线程平安的容器,它对外部的每个办法都简略粗犷的上锁,防止多线程引发的安全性问题,但通常这种同步形式须要的开销比拟大,因而,拜访元素的效率远远低于ArraryList

扩容上,ArraryList扩容后的数组长度会减少 50%,而 Vector 的扩容长度后数组会增加一倍。

LinkedList 类

LinkedList是一个双向链表,容许存储任何元素。特色如下

  • LinkedList所有的操作都能够体现为双向性的,索引到链表的操作将遍历从头到尾,视哪个间隔近为遍历程序。
  • 留神这各市县不是线程平安的,如果多个线程并发拜访链表,并且至多其中的一个线程批改了链表构造,那么这个链表必须进行内部桎梏。或者应用

    List list = Collection.synchronizedList(new LinkedList(...))

Stack

栈堆是咱们常说的 后入先出 容器。它继承了 Vector 类,提供了罕用的 pushpop操作,以及在栈顶的 peek 办法,测试 stack 是否为空的 empty 办法,喝一个寻找与栈顶间隔的 search 办法。

第一次创立栈,不蕴含任何元素。一个更欠缺,可靠性更强的 LIFO 栈操作由 Deque 接口和他的实现提供,应该优先应用这个类。

Deque<Integer> stack = new ArraryDeque<Integer>()

HashSet

HashSetSet 接口的实现类,由 HashMap 反对(实际上 HashSetHashMap的一个实例)。它不能保障汇合的迭代程序。这个类容许 null 元素。

  • 留神这个实现不是线程平安的,如果多线程并发拜访 HashSet,并且至多一个线程批改了set,必须进行内部桎梏。或者应用Collections.synchronizedSet() 办法重写。
  • 这个实现反对 fail-fast 机制。

TreeSet

TreeSet是一个基于 TreeMapNavigableSet实现。这些元素应用它们的天然排序或者在创立时提供的 Comparator 进行排序,具体取决于应用的构造函数。

  • 此实现为基本操作,add,removecontains 提供了 log(n) 的工夫老本。
  • 留神这个实现不是线程平安的。如果多线程并发拜访TreeSet,并且至多一个线程扭转了Set,必须进行内部加锁。或者应用

    SortedSet s = Collections.synchronizedSortedSet(new TreeSet(...))

LinkedHashMap 类

LinkedHashMapMap 接口的 Hash 表和链表的实现。这个实现与 HashMap 不同之处在于它保护了一个贯通其所有条目标双向链表。这个链表定义了遍历程序,通常是插入 map 中的程序。

  • 它提供了一个非凡的 LinkedHashMap(int, float, bloolean) 结构器来创立LinkedHashMap,其遍历程序是其最初一次拜访的程序。
  • 能够重写 removeEldestEntry(Map.Entry) 办法以便在将新映射增加到 map 时强制删除过期映射的策略。
  • 这个类提供了所有可抉择的 map 操作,并且容许 null 元素。因为保护链表的额定开销,性能可能会低于 HashMap, 有一条除外:遍历LinkedHashMap 中的 collection-views 须要与 map.size 成正比,无论其容量如何。

Hashtable 类

IdentityHashMap 类

WeakHashMap 类

Collection 类

Collection不属于 Java 框架继承树上的内容,它属于独自的分支,Collection是一个包装类,它的作用就是为了汇合框架提供某些性能实现,此类只包含静态方法操作或者返回collections

同步包装

同步包装讲主动同步(线程安全性)增加到任意汇合。六个外围汇合接口(Collection,Set,List,Map,SortedSet,SortedMap)中的每一个都有一个动态工厂办法。

public static Collection synchronizedCollection(Collection c);
public static Set synchronizedSet(Set s);
public static List synchronizedList(List list);
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m);
public static SortedSet synchronizedSortedSet(SortedSet s);
public static <K,V> SortedMap<K,V> synchronizedSortedMap(SortedMap<K,V> m);

不可批改的包装

不可批改包装的包装器通过拦挡批改汇合的操作并抛出UnSupportedOperationException,次要用在上面两个情景:

  • 构建汇合后使其不可扭转。在这种状况下,最好不要去获取返回 collection 的援用,这样有利于保障不变性
  • 容许某些客户端以只读形式拜访你的数据结构。你保留对返回的 collecton 的援用,但散发对包装器的援用。通过这种形式,客户能够查看但不能批改,同时放弃齐全拜访权限。

这些办法是:

public static Collection unmodifiableCollection(Collection<? extends T> c);
public static Set unmodifiableSet(Set<? extends T> s);
public static List unmodifiableList(List<? extends T> list);
public static <K,V> Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m);
public static SortedSet unmodifiableSortedSet(SortedSet<? extends T> s);
public static <K,V> SortedMap<K, V> unmodifiableSortedMap(SortedMap<K, ? extends
V> m);

线程平安的 Collections

泛型

JDK1.5 中,提出一个新的概念,那就是泛型:

泛型其实就是一种参数化的汇合,它限度了太你家进汇合的类型。泛型的实质就是一种参数化的类型。多态能够看作是泛型的机制。一个类继承了父类,那么就能通过它的父类找到对应的子类,然而不能通过其余类来找到具体要找的这个类。泛型的设计之初就是心愿对象或办法具备最宽泛的表达能力。

上面是一个没有泛型的栗子

List arrayList = new ArrayList();
arrayList.add("cxuan");
arrayList.add(100);

for(int i = 0; i< arrayList.size();i++){String item = (String)arrayList.get(i);
     System.out.println("test =", item);
}

因为 Integer 类型不能强行转换为 String 类型所以会报谬误:

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

用泛型改写:

List<String> arrayList = new ArrayList<String>();

arrayList.add(100);

泛型的应用

泛型很多用法,用好泛型很牛

用泛型示意类

泛型能够加在类下面,来示意这个类的类型

// 此处 T 能够随便写成任何标识
public class GenericDemo<T>{
 //value 这个成员变量的类型为 T,T 的类型由内部指定
    private T value;
    
    public GenericDemo(T value) {this.value = value;}
    
    public T getValue(){ // 泛型办法 getKey 的返回类型为 T,T 的类型由内部制订
        return value;
    }
    
    public void setValue(T value){this.value = value}
}

用泛型标识接口

泛型接口与泛型类的定义及应用基本相同。

// 定义一个泛型接口
public interface Generator<T>{public T next();
}

个别泛型接口罕用于 生成器 (generator) 中,生成器相当于对象公擦汗惆怅,是一种专门用来创建对象的类。

泛型办法

能够应用泛型来示意办法

public class GenericMethods{public <T> void f(T x){System.out.println(x.getClass().getName());
    }
}

泛型通用符

List是泛型类,为了示意各种泛型 List 的父类,能够应用类型通配符,类型通配符应用 问号(?)示意,它的元素类型能够匹配任何类型。例如:

public static void main(String[] args){List<String> name = new ArraryList<String>();
    List<Integer> age = new ArraryList<Integer>();
    List<Number> number = new ArraryList<Number>();
    name.add("cxuan");
    age.add(18);
    number.add(314);
    generic(name);
    generic(age);
    generic(number);
}

public static void generic(List<?> data){System.out.println("Test cxuan :" + data.get(0));
}

上界通配符 <? extends ClassType> 该通配符为 ClassType 的所有子类型。它示意的是任何类型都是 ClassType 类型的子类。

下届通配符 <? super ClassType> 改通配符为 ClassType 的所有超类型,它示意的是任何类型的父类都是ClassType

反射

反射是 Java 中一个十分重要同时也是一个高级特色,基本上 Spring 等一系列框架都是基于反射的思维写成的。

Java 反射机制是在程序的运行过程中,对于任何一个类,都能晓得它的所有属性和办法;对于任何一个对象,都可能晓得调用它的任意属性和办法,这种动静获取信息以及动静调用对象办法的性能被称为 java 语言的反射机制。

反射机制次要提供了一下几个性能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时结构任意一个类的对象
  • 在运行时判断任意一个类所有的成员变量和办法
  • 在运行时调用任意一个对象的办法

由此,反射就像是一个掌控全局的角色,不论你程序怎么运行,我都可能晓得你这个类有哪些属性和办法,你这个对象由谁调用。

在 java 中,应用 java.lang.reflect 包实现了反射机制。

上面是一个简略的反射类:

public class Person{
    public String name;
    public int age;
    
    public Person(){super();
    }
    
    public Person(String name, int age){super();
        this.name = name;
        this.age = age;
    }
    
    public String showInfo(){return "name=" + name + ", age=" + age;}
}

public class Student extends Person implements Study{
    public String className;
    private String address;
    
    public Student(){super();
    }
    
    public Student(String name, int age, String className, String address){super(name, age);
        this.className = className;
        this.address = address;
    }
    
    public Student(String className){this.className = className;}
    
    public String toString(){return "姓名:" + name + ",年龄" + age + ",班级" + className + ",住址:" + address;}
    
    public String getAddress(){return address;}
    
    public void setAddress(String address){this.address = address;}
}

public class TestRelect {public static void main(String[] args){
        Class student = null;
        try{student = Class.forName("com.cxuan.reflection.Student");
        }catch (ClassNotFoundException e){e.printStackTrace();
        }
        
        // 获取对象的所有私有属性
        Field[] fields = student.getFields();
        for (Fidld f : fields){System.out.println(f);
        }
        System.out.println("----------------");
        // 获取对象所有属性,但不蕴含继承的
        Field[] declaredFields = student.getDeclaredFields();
        for (Field df : declareFields) {System.out.println(df);
        }
        
        // 获取对象的所有公共办法
        Method[] methods = student.getmethods();
        for (Method m : methods){System.out.println(m);
        }
        
        // 获取对象所有办法,但不蕴含继承的。Method[] declaredMethods = student.getDeclaredMethods();
        for (Method dm : declaredMethods){System.out.println(dm);
        }
        
        // 获取对象所有的公共构造方法
        Constructor[] constructors = student.getConstructors();
        for (Contructor c : constructors){System.out.println(c);
        }
        
        // 获取对象所有的构造方法
        Constructor[] declaredConstructors = student.getDeclaredConstructors();
        for (Constructor dc : declaredConstructors){System.out.println(dc);
        }
        
        Class c = Class.forName("com.cxuan.reflection.Student");
        Student stu1 = (Student)c.newInstance();
        // 办法 1:实例化默认构造方法,调用 set 赋值
        stu1.setAddress("山东");
        System.out.println(stu1);
        
        // 办法 2:获得全副的构造函数,应用构造函数赋值
        Constructor<Student> constructor = c.getConstructor(String.class, int.class, String.class, String.class);
        Student stu2 = (Strudent) constructor.newInstance("cxuan", 24, "1 班", "山东");System.out.println(stu2);
        
        /**
        * 获取办法并执行办法
        */
        Method show = c.getMethod("showInfo");        // 获取 showInfo()办法
        Object object = show.invoke(stu2);        // 调用 showInfo()办法} 
}

Class 类

Field 类

Method 类

ClassLoader 类

枚举

枚举可能是咱们应用次数比拟少的个性,在 Java 中,枚举应用 enum 关键字来示意,枚举其实是一项十分有用的个性,能够了解为具备特定性质的类。enum不仅仅 java 有,CC++ 也有枚举的概念。

public enum Family{
    
    FATHER,
    MOTHER,
    SOM,
    DAUGHTER;
}

如上创立了一个 Family 的枚举类,它具备 4 个值,因为枚举类型都是常量,所以都用大写字母来示意。那么 enum 创立进去了,如何援用?

public class EnumUse{public static void main(String[] args){Family s = Family.FATHER;}
}

枚举个性

enum类当创立实现后,编译器会主动为 enum 增加 toString() 办法,可能不便显示 enum 实例的具体名字是什么。除了 toString() 办法,编译器还会增加 ordinal() 办法,这个办法用来示意 enum 常量的申明程序,以及 values() 办法显示程序的值。

public static void main(String[] args){for(Family family : Family.values()){System.out.println(family + ", ordinal" + fmamily.ordinal());
    }
}

enum能够进行动态导入包,动态导入包能够做到不必输出 枚举类名. 常量 ,能够间接应用常量,应用enumstatic关键字能够做到动态导入包。

枚举和一般类一样

枚举和一般类一样,除了枚举中可能方百年快捷的定义 常量 ,咱们日常开发应用的public static final xxxx 其实都能够用枚举来定义。在枚举中可能定义属性和办法。

public enum OrdinalEnum{WEST("live in west"),
    EAST("live in east"),
     SOUTH("live in south"),
    NORTH("live in north");
    
    String description;
     OrdinalEnum(String description){this.description = description;}
    
    public String getDescription() {return description;}
    
    public void setDescription(String description) {this.description = description;}
    
    public static void main(String[] args) {for(OrdinalEnum ordinalEnum : OrdinalEnum.values()){System.out.println(ordinalEnum.getDescription());
         }
    }
}
退出移动版