1、标识符的命名规则和命名规范

    命名规则:1、不能使用关键字、标识符;2、不能使用空格; 如果不遵守编译不通过
    命名规范:1、包名 xxxyyyzzz; 2、类名(接口名)XxxYyyZzz; 3、变量名(方法名)xxxYyyZzz; 4、常量名: XXX_YYY_ZZZ

    2、Java基础类型

    按照数据类型分为:
    image.png

    Java数据类型分为两类: 非引用和引用类型: 非引用:byte(1字节)、char(2字节)、short(2字节)、int(4字节)、long(8字节)、float(4字节)、double(8字节)、boolean(1位) 8种类型。 引用数据类型: 类、接口、数组。

    long类型需要带上L(l)结尾
    float类型需要以F(f)结尾
    在Java当中, ‘’为字符; “”为字符串。 ‘好’也是一个字符。

    按照在类型声明的位置:
    image.png

    2、整型提升

    byte、short、char ->int ->long ->float ->double, char类型和int相加会将char提升为int类型进行运算。
    概念: 容量小的类型与容量大的类型进行运算时会自动提升为容量大的类型。
    Java当中byte、char、short之间运算时会提升为int类型,最后再降为对应的类型。由于Java类型严格,所以就会报错。必须用int接受。

    image.png

    无符号右移; 无符号右移补0。

    2.1 强制类型转化

    强制类型转化会存在数据的丢失和精度问题。容量大的转化容量小的。

    3、Java关键字的使用
    image.png

    凡是自己的起的变量的名字都是标识符。(包名、类型名、接口名、方法名、 常量名)

    4、switch() 里面可以是哪些类型?

    byte、short、char、int, 枚举类型、String。

    5、数组的初始化方式?

    数组是引用类型。
    int[] arr = new int[5]; //动态初始化
    int[] arr = new int[]{1,2,3,4,5}; //静态初始化
    上面的长度一创建就确定啦, 就是不可以修改。

    二维数组创建方式:
    二维数组类型其实也是一维数组类型。
    int[][] arr = new int[5][4];
    int[][] arr = new int[5][];
    int[][] arr = new int[][] {{1,2,3}, {4,5}, {6,7,8}}; 大小为3行3列
    数组初始化会创建默认值: 整形:0; 浮点型:0.0; char:0; boolean: false, 引用类型: null
    数组常见的异常为: 1、角标越界问题; 2、空指针问题。

    6、所有排序算法以查找算法

    冒泡排序: o(n)~o(n^2)
    image.png

    7、面向对象

    7.1 类及类的成员: 属性、方法、构造器、代码块、内部类。
    7.2 特点: 封装、继承、多态。
    封装: 对代码内部的保护,该隐藏的隐藏起来,不该隐藏的暴露出来。
    体现1:对于内部的私有属性可以通过提供共有的接口对外提供。
    体现2:不对外暴露的私有方法
    体现3:单例模式
    体现4:不希望类在包外访问,可以将类设置为缺省的。
    继承(extends): 1、提高代码复用性; 2、扩展功能;3、为多态做准备
    子类继承父类就会获取父类所有的属性和方法,可能后续会因为父类的私有属性导致子类无法访问而已。
    1)Java类只有单继承,所以一个父类可以被很多子类继承,一个子类只能有一个父类
    2)子类继承父类,就可以获取父类的属性和方法。
    3)子类实例化的时候,会先调用父类的构造器,后调用自己的构造器。
    4)没有声明一个类的父类的话,这个类继承于java.lang.Object类。也就是所有的类都继承或间接继承Object
    多态: 父类的引用指向子类的对象。多态的实现其实就是虚拟方法的调用, 在编译阶段我们只能调用父类中声明的方法, 在运行期调用子类重写的方法。 编译看左边, 运行看右边。由于这个判断无法在编译阶段确定,只能在运行阶段确定,所以也叫运行时绑定(动态绑定)。
    多态分为: 编译时多态 和 运行时多态
    this和super调用构造器: 本类重载其他的构造器; 调用父类的构造器。

    Java这块每个函数都具有虚函数的特征,区别C++好需要virtual关键字修饰。正是因为这个特征,Java的多态很容易实现。如果使用fianl关键字修饰,就不会存在多态了,编译阶段就会确定是调用哪个方法。

    子类实例化过程: 首先调用父类的构造器,然后再调用子类的构造器。先完成父类的初始化,然后在完成子类的初始化。

    7.3 类和对象的区别: 类像一个模板, 对象是实例化、实实在在的。
    7.4 类和对象创建和执行分为几步: 1、类创建;2、类实例化;3、调用。
    7.5 this是本类的引用, super是父类的引用。

    7.6 属性和局部变量的区别?
    1、局部变量在栈中, 属性在堆中(非static)
    2、局部变量不初始化, 属性会自动初始化。

    8、函数重载&函数重写

    函数重载: 同一作用域相同的函数名、参数类型和个数,参数排布顺序不同就是函数重载,它是在编译阶段就确定好的,也被称为静态绑定。
    函数重写:函数体相同(函数名,参数类型和参数排布顺序相同),子类的返回值是父类的返回值的子类即为函数重写。权限修饰符也要一样。
    由于在编译阶段无法确定具体行为,也就是调用父类的方法, 在运行阶段就会调用子类重写的方法。因此也被称为动态绑定。
    Java这块我们可以通过@Override校验重写是否成功, 如果重写失败会报错。
    image.png
    找到操作数栈的实际类型C, 然后去invokevirtual去在常量区找相符方法, 如果不通过就会按照继承关系依次对C执行查找相符方法,最终找到了则返回这个方法的直接引用执行方法内容,如果没找到则抛出异常 IllegalAccessError 非法访问异常。

    但是这样存在一个问题,就是每次遇到一个多态就会网上找几次才能找到?
    image.png
    因此诞生虚方法表(存放虚方法)
    最终多态的底层实现为: 找到操作数栈实际类型C,然后在虚方法表中查找执行。
    虚方法表在类加载的链接阶段进行创建。

    image.png

    虚方法和非虚方法?

    非虚方法: 如果在编译阶段就确定调用方法版本,在运行期间不会发生变化的。
    例如: static修饰的静态方法,final修饰的方法,构造器,私有方法,父类的方法。
    除此以外,Java默认每个方法都是虚方法,在运行阶段实际调用可能会发生改变。

    9、值传递机制

    实参:方法调用时,实际传递给形参的数据
    形参:方法定义时,声明的小括号内的参数
    如果参数是基础数据类型,此时形参接受的实参的存储的数据值, 如果参数是引用类型,此时形参传递的是地址值。

    10、何为JavaBean

    JavaBean使用Java写的一个可重复使用的组件。需要满足以下三个条件:
    1、类是公共的;2、有一个无参构造函数;3、有属性,并且有set、get方法。

    11、MVC设计模式
    MVC分为三层: model层、 views层、 controller层, 将web开发流程分层,层次分明。
    image.png
    12、构造器(构造方法)有什么用?

    1. 创建对象
    2. 一个类初始化的时候会调用构造器初始化属性。
    3. 一个类可以创建多个构造器。
    4. 一个类一定会有一个默认的构造器(无参),如果手写构造器就会覆盖默认的构造器。
    5. 一个类至少含有一个构造器。

    关于类的属性赋值,有几种赋值方式?
    默认初始化、显式初始化、构造器初始化

    this关键字可以调用哪些结构?
    非static属性、 非static方法、 构造器。

    Java类中权限修饰符有哪些? 说明各自的权限范围?
    image.png
    权限由高到底: public > protected > 默认 > private

    13、可变参数

    public static void main(String[] args) {
    show(“asd”, “xcx”, “dsd”);
    }
    public static void show(String … strs) {
    for (String str : strs) {
    System.out.println(str);
    }
    }

    14、何为向下转型?

    将父类引用指向的对象交给子类引用指向。如果说父类指向的是子类,那就是把权限交给子类而已。不会存在安全问题。
    使用强转符就可以。

    instanceOf关键字
    a instanceOf A 检查a对象是否为A的对象,是返回true,否则编译错误。

    15、Object对象

    所有的类对象都直接或者间接继承了Object类。
    image.png

    16、三者类型转换-基础数据类型、包装类、String
    image.png
    基本数据类型<—->包装类 自动装箱和拆箱
    基本数据类型、包装类—->String, String.valueOf()
    String —-> 基本数据类型, 调用包装类的IparseXxx(String s)
    可能会出现异常,NumberFormatException

    17、main方法

    1. main方法作为程序的入口
    2. main是一个普通的静态方法
    3. main也是我们与控制台交互的方式。 args读取的是控制台输入的信息。

    代码块的作用:用于初始化类、对象信息。也只能使用static修饰符。
    类的成员: 属性、方法、构造器、代码块。

    static修饰的代码块: 随着类的加载而执行, 只执行一次。执行顺序按照先后顺序。
    非static修饰的代码块:
    image.png

    17、抽象类以及abstract关键字

    随着继承重写越来越深,导致后面都是创建子类,使用父类引用使用。 导致父类基本上不会实例化,不再使用。这样针对这种类型,父类只是定义,不是声明。 就提升为抽象类。

    抽象类不能实例化,但是可以有构造器,方便子类继承时调用。

    包含抽象方法的类一定是抽象类,反之不成立。
    抽象方法只能定义,由子类完成实现。
    如果子类继承抽象类,但是没有实现所有的抽象方法,则子类也不能实例化(编译阶段就会报错)(当然普通的方法也可以重写。)
    若子类没有重写父类的所有方法, 则子类也是一个抽象类。

    1. abstract修饰一个类,这个类也是抽象类。
    2. 包含抽象方法的类是抽象类,但抽象类不一定包含抽象方法
    3. 抽象类可以有构造器和自定方法
    4. 子类继承抽象类需要实现所有抽象方法,否则无法实例化,除非也是抽象类。
    5. abstract只能修饰类、方法;其他的属性都不可以修饰,也不能修饰静态方法,尤其是final。

    匿名类使用:

    1. Person person = new Person() {
    2. @Override
    3. public void eat() {
    4. System.out.println("haha");
    5. }
    6. };

    抽象类和接口有哪些共同点和区别?

    1. 相同点: 不能实例化、都可以被继承
    2. 不同点: 抽象类有构造器,接口不能声明构造器,抽象类只能单继承,接口能够被多继承。

    如果一个类既有继承类又有实现接口,则先写extends后写implements。

    模板方法设计模式:
    image.png
    18、interface接口

    接口的出现是为了弥补C++多继承。

    1. 使用interface关键字修饰
    2. 接口中定义的变量默认为全局常量(则为public static final)
    3. 接口中是不能定义构造器
    4. 接口中定义的方法都是抽象方法,子类继承需要全部重写(省略了public abstract)

    接口与接口之间可以继承,多继承。
    接口也可以实现匿名内部类。

    工厂模式:创建对象的实现。实际上最好的实现方式是通过反射的模式进行创建。
    如果接口和继承父类中都含有相同的属性,则编译错误。

    Java8接口新特性:让接口越来越像类,接口能够提供一定的方法供子类使用。
    image.png
    可以定义静态方法、默认方法。
    接口中定义的静态方法只能接口本身调用,子类无法调用。
    但是子类可以调用接口的默认方法, 也可以重写。
    如果子类继承的父类和实现的接口中声明同名同参数的方法, 默认调用父类的方法,但是对于属性不行。这也是类优先原则。

    1. 接口定义的静态方法,只能通过接口调用
    2. 通过实现类的对象,可以调用接口中的默认方法
    3. 如果子类重写了默认方法, 则调用为重写的默认的。
    4. 如果继承多个接口中有同名同参数的默认方法, 如果不重写则报错。但是如果有继承类存在该方法,则根据类优先原则使用父类的。可以不重写。

    如果想要在子类调用抽象类的默认方法-> 接口名.super.方法名。

    19、内部类

    内部类分为局部内部类(静态和非静态)和成员内部类(方法类、代码块类、构造器类)。

    1. class Person1 {
    2. // 成员内部类
    3. class CC {
    4. }
    5. // 局部内部类
    6. public void method() {
    7. class AA {
    8. }
    9. }
    10. // 局部内部类
    11. {
    12. class BB {
    13. }
    14. }
    15. }
    1. 内部类作为外部类的属性,可以访问外部类的一些信息。
    2. 可以被static修饰
    3. 可以被4种不同的权限修饰
    4. 作为一个类,也可以final、abstract关键字修饰

    对于静态内部类实例化对象:Person1.CC cc = new Person1.CC();
    非静态内部类实例化对象: Person1 p = new Person1(); Person1.CC cc = p.new CC();

    在内部类中无法更改方法中的局部变量。一般安卓开发会使用。

    1. public class InnerClass {
    2. public void method() {
    3. int num = 10;
    4. class AA {
    5. public void show() {
    6. // 对于num来说, num就是常量,不能更改
    7. num = 20;
    8. System.out.println(num);
    9. }
    10. }
    11. }
    12. }

    20、 异常

    Java异常分为两类:1、Error; 2、Exception(语法错误和逻辑错误不属于异常)
    Error:Java虚拟机无法解决的严重问题。比如StackOverFlowError和OOM。(我们无法通过代码解决)
    Exception:空指针、角标越界等等。

    1. 异常分为编译型异常和运行时异常。
    2. 编译型异常源文件在被类加载器加载阶段, 而运行时异常则是加载好之后的问题。
    3. 编译型异常也被称为受查异常,而运行时异常则被称为非受查异常。
    4. 除了RuntimeException异常,其他的都是编译型异常,受查异常。
    5. 一般需要异常处理的都是受查异常, 编译时异常。

    image.png

    对于异常处理有两种:1、try-catch; 2、throw

    1. 即使catch中抛出异常处理return,finally中也会执行。
    2. 需要注意的是:对于物理方面的资源,连接池,等等需要手动释放,不会自动回收
    3. 还可以通过throw自定义抛出异常。
    4. 通过继承Exception类实现自定义异常。
    5. throw为手动抛出异常,throws表示该方法会抛出什么异常

    final和finally和finalize三者的区别?

    1. final修饰类、属性、方法,无法继承,无法修改,无法重写
    2. finally无论异常是否发生都会执行
    3. finalize是类被销毁时所执行的方法。

    比较throw和throws的区别?

    1. throw抛出异常对象,可以手动抛出一个异常。
    2. throws标记一个方法会抛出什么样的异常,调用该方法需要做异常处理。try-catch-finally

    21、String、StringBuilder和StringBuffer区别

    1)String是不可变的类,里面的内容不能修改
    2)String类无法被继承

    String是不可变的类,StringBuilder和StringBuffer是可变的。

    1. StringBuilder线程不安全,效率高;
    2. StringBuffer是线程安全的。效率低,它保证线程安全是通过所有方法加synchronzied监视器。

    22、日期和时间

    1. System.currentTimeUnit() : System提供的静态方法,单位毫秒级。
    2. Date类分为uti提供的,和sql提供的。
    3. sql下Date继承于util下的Date。

    SimpleDateFormat: 时间格式化和解析
    :.format(java.util.Date) 格式化
    :.prase(“19-12-18 上午11:34”)

    1. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
    2. System.out.println(simpleDateFormat.format(date));
    3. // 2022-04-06 07:53:18
    4. // 转化为Date
    5. String birth = "2020-09-08";
    6. SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
    7. System.out.println(simpleDateFormat.parse(birth));
    8. // util.Date 转化为 sql.Date
    9. java.sql.Date date1 = new java.sql.Date(date.getTime());
    1. // 日期转化为天数
    2. Date date = new Date();
    3. System.out.println(date);
    4. System.out.println(date.getTime()); //获取毫秒数
    5. int days = data.getTime() / (1000*60*60*24) + 1; // 对应的天数

    1、calender抽象类(日历类) JDK1.7以前提供的。
    2、Java提供了时间管理API(java-Time)1.7之前抛弃了

    1. LocalDate localDate = LocalDate.now(); 2022-04-06
    2. LocalTime localTime = LocalTime.now(); 20:36:55.221
    3. LocalDateTime localDateTime = LocalDateTime.now(); 2022-04-06T20:36:55.221
    4. LocalDateTime localDateTime1 = LocalDateTime.of(2022, 11, 23, 12,23,46); 2022-11-23T12:23:46
    5. System.out.println(localDateTime1.getDayOfMonth()); //这个第几天
    6. System.out.println(localDateTime1.getDayOfWeek()); //周几
    7. System.out.println(localDateTime1.getMonth()); //几月
    8. System.out.println(localDateTime1.getMonthValue()); //几月数字
    9. System.out.println(localDateTime1.getMinute());//分钟

    JDK8提供的DateTimeFormat为新的格式化时间类。
    image.png

    编码和解码:
    1、编码:字符串->字节
    2、解码:字节->字符串

    日期格式化和解析:
    1、格式化: 日期->字符串, format
    2、解析:字符串->日期,parse

    JDK8前后的时间函数对比:
    image.png

    23、比较器Compare

    针对对象的排序, 使用java.long.Comparable和 java.util.Comparator两个接口。

    Comparable需要继承该接口,并且完成重写。
    如果不想继承接口而排序,则使用下面的接口。
    java.util.Comparator 定制排序:

    1. TestCompare[] arr1 = new TestCompare[5];
    2. arr1[0] = new TestCompare("A", 1);
    3. arr1[1] = new TestCompare("B", 2);
    4. arr1[2] = new TestCompare("C", 3);
    5. arr1[3] = new TestCompare("D", 4);
    6. arr1[4] = new TestCompare("E", 5);
    7. Arrays.sort(arr1, new Comparator<TestCompare>() {
    8. @Override
    9. public int compare(TestCompare o1, TestCompare o2) {
    10. if (o1.getName().compareTo(o2.getName()) < 0) {
    11. return 1;
    12. } else if (o1.getName().compareTo(o2.getName()) > 0) {
    13. return -1;
    14. } else {
    15. return o1.getAge() - o2.getAge() > 0 ? -1 : 1;
    16. }
    17. }
    18. });
    1. Comparable排序,需要继承Comparable接口,并实现CompareTo方法。
    2. Comparator则不需要继承实现,对于一个对象可以直接定义比较规则。

    24、常见类对象

    1、System类

    1. System.exit() 退出
    2. System.gc() 请求系统垃圾回收,具体回收取决于系统的GC情况和算法和执行情况。
    3. image.png

    2、Math类
    image.png
    3、BigInteger(可以构建大于Long范围任何精度的整数,大数问题)
    image.png
    4、BigDecimal (对应浮点型)可以支持任意精度的浮点数。

    25、枚举类和注解

    1. 枚举类,当需要定义一组常量,强烈建议使用枚举类。
    2. 类的对象有限的,确定的,我们称此类为枚举类。
    3. 如果枚举类只有一个, 使用单例模式。

    JDK5之前通过public私有化构造器实现枚举类
    5以后用过enmu关键字创建枚举类。

    1. class Season {
    2. private final String seasonName;
    3. private final String seasonDesc;
    4. private Season(String seasonName, String seasonDesc) {
    5. this.seasonName = seasonName;
    6. this.seasonDesc = seasonDesc;
    7. }
    8. public static final Season SPRING = new Season("春天", "万物复苏");
    9. public static final Season SUMMER = new Season("夏天", "知声了了");
    10. public static final Season AUTUMN = new Season("秋天", "枫红落叶");
    11. public static final Season MINTER = new Season("冬天", "鹅毛大雪");
    12. public String getSeasonName() {
    13. return seasonName;
    14. }
    15. public String getSeasonDesc() {
    16. return seasonDesc;
    17. }
    18. }
    19. public enum TestEnmu {
    20. SPRING("春天", "万物复苏"),
    21. SUMMER("夏天", "酷酷烈日"),
    22. AUTUMN("秋天", "秋高气爽"),
    23. WINTER("冬天", "冬去春来");
    24. private final String name;
    25. private final String desc;
    26. private TestEnmu(String name, String desc) {
    27. this.name = name;
    28. this.desc = desc;
    29. }
    30. public String getName() {
    31. return name;
    32. }
    33. public String getDesc() {
    34. return desc;
    35. }
    36. }
    37. // 通过如下方式来使用
    38. Season s = Season.SPRING;
    39. s.getSeasonName()
    40. s.getSeasonDesc()
    1. 什么是枚举类:类中的对象是有限个,构造器私有化,如果只有一个为单例模式
    2. 对于枚举使用 public static final
    3. 对于属性 public final

    26、注解

    Annotation是代码中里的特殊标记,这些标记在编译、类加载、运行时读取,并执行相应的操作。
    可以在不改变原有逻辑的情况下,在源文件中嵌入一些信息。
    可以用于修饰包、类、构造器、方法、成员变量、参数、局部变量。

    1、自定义注解:

    1. 自定义注解继承了java.lang.annotation.Anntation接口
    2. 注解的参数类型只能是String、Class、enum、Annotation类型
    3. 可以设置默认值default
    4. 只有一个参数,建议使用value
    5. 如果一个注解没有成员,则表明这是一个标识作用。

    image.png
    2、元注解

    修饰注解的注解则称为元注解。

    1. Retention:修饰Annotation的证明周期,有SOURCE、CLASS、RUNTIME三种,其中CLASS为默认。如果想要在运行阶段通过反射获取注解,只能声明为RUNTIME中,其他两者更偏向于编译时和运行时校验。
    2. Target:表示注解能够修饰哪些元素。TYPE(类,接口,枚举类),FIELD(属性),PARAMETER(形参),LOCAL_VARIABLE(修饰局部变量),不选默认全部属性都可以。
    3. Doucumented:表示修饰的注解被javadoc解析时,保留下来。默认不保留。生成API文档时会有这个标识。
    4. Inherited:被它修饰的Annotation具有继承性,如果某个子类使用了被Inherited修饰的注解,其子类会自动继承这个注解。子类也能够继承使用父类的注解。

    3、通过反射获取注解信息

    1. public static void main(String[] args) {
    2. Class<Main01> aClass = Main01.class;
    3. Annotation[] annotations = aClass.getAnnotations();
    4. for (Annotation annotation : annotations) {
    5. System.out.println(annotation);
    6. }
    7. }

    4、JDK8提供的注解:可重复注解和类型注解

    可重复注解:

    1. 老的重写方式
    2. @MyAnnotations({@TestAnnotation, @TestAnnotation})
    3. public @interface MyAnnotations {
    4. TestAnnotation[] value();
    5. }
    6. 新的写法通过@Repeatable(MyAnnotations.class)完成重复写绑定
    7. // 这个MyAnnotations里面必须和TestAnnotation一定的生命周期和修饰范围和一定的继承性
    8. @Repeatable(MyAnnotations.class)
    9. @Retention(RetentionPolicy.RUNTIME)
    10. @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
    11. public @interface TestAnnotation {
    12. String value() default "你好";
    13. }
    14. @TestAnnotation
    15. @TestAnnotation
    16. public static void main(String[] args) {

    类型注解:针对一些特殊的参数进行修饰

    1. 能够在类的形参接受这块使用
    2. class Generic<@TestAnnotation T> {
    3. }
    4. 这个是不能被使用的,需要添加新的修饰范围TYPE_PARAMETER才可以。
    5. ArrayList<@TestAnnotation String> list = new ArrayList<>();
    6. 这个则是需要修饰范围TYPE_USE修饰即可。
    1. 何为元注解:对注解进行修饰的注解就是元注解
    2. Retention修饰生命周期(SOURCE、CLASS、RUNTIME);SOURCE编译检验,但是生成的.class不会包含;CLASS会在.class保留,但是不会在运行时空间保留,默认行为;RUNTIME会运行时内存中。一般通过反射获取注解进行相关操作。
    3. TARHET修饰范围类型
    4. 还有JDK8提供可重复直接REPEATED和USETYPE

    什么叫注解?

    1. JDK5新增的功能,在不改变原有代码逻辑的情况下,添加一些标记,这些标记可以在编译,类加载,运行阶段读取。并执行的处理,也就是再不改变原有的逻辑下新增一些判断和处理
    2. 在EE中,可以代替xml配置进行处理。

    JDK内置的注解?

    1. Override, 编译阶段判断是否重写
    2. Deprecated, 编译阶段判断该内容过时
    3. SuppressWarinings,抑制编译器警告

    27、集合

    Java集合可以分为两个体系: Collection接口和Map接口

    1. Collection接口: 一组集合的数据(List,Set)
    2. Map: key-value通过key值获取value

    Collection接口:
    image.png
    Map接口:
    image.png
    image.png

    集合和数组的区别?

    1. 数组和集合都是对多个数据进行存储和管理的结构,简称Java容器
    2. 两者都是存储,但是不能持久化,都是在内存中存储
    3. 数组的存储数据是固定大小的,而集合可以自动扩容。

    数组的缺点?

    1. 一旦初始化,长度不会改变。
    2. 提供的方法有限,对于增加和删除效率不高。
    3. 集合的诞生就是为了解决数组的缺点,代替数组。

    ArrayList、LinkedList、Vector三者的区别?

    1. 三者都是实现了List接口,都是对数据进行存储。
    2. ArrayList和Vector底层都是通过动态的数组的实现的,内存资源连续,空间利用率好,对于数据的增加和删除性能差。便于数据的查询。
    3. LinkedList底层通过链表实现,空间利用率不高,可能会存在内存碎片,对于数据的增加和删除效率高,但是不能快速查询任意位置的数据。
    4. ArrayList和Vector,ArrayList线程不安全,效率高,Vector线程安全,效率低。

    1、contain()会调用存储对象的equals()方法进行判断是否匹配。
    2、ArrayList默认长度为10,新增元素时扩容为原来容量的1.5倍。

    Set集合介绍:

    HashSet: 存储无序、不可重复的数据。读取效率高, 线程不安全的。
    LinkedHashSet: 继承HashSet,遍历其内部数据时,可以按照添加的顺序遍历
    TreeSet: 底层通过红黑树实现, 前序遍历得到有序的。

    对于HastSet对象比较来说:通过hashCode方法获取哈希值判断是否相等。
    所以对于存放在Set中的对象,对应的类一定要重写equals()和hashCode方法。
    HashSet实际上就是调用HashMap实现的。

    LinkedHashSet继承HashSet, 它能够保证遍历出来的元素按照插入的元素。底层还是和HashSet一样的性能。
    底层实现:插入元素有三个,一个前驱引用和后驱引用,按照插入的顺序将元素链接起来形成双向链表。

    image.png起始头节点为null。

    而对于TreeSet来说底层通过红黑树实现,会进行比较,因此需要存放的元素具有比较的能力。
    对于对象来说需要实现comparable方法。
    对于HashSet来说,比较两个对象是否相同通过HashCode()判断,而对于TreeSet则是通过对象的比较器来判断的。

    集合Collection中存储自定义类的对象,需要自定义对象重写哪些方法?

    1. equals()方法, 虽然List不会排序,但是remove,contains方法需要判断对象是否相同需要。
    2. Set中HashSet需要重写HashCode和equals方法, 因为Set要去重,需要判断对象之间是否相同,依据就是HashCode值。而TreeSet需要排序,则需要对象之间重写比较器来进行排序。

    可以试试,List不重写equals,remove和contains方法能否使用。

    Set提供的remove方法和add方法,会调用equals和hashCode方法匹配。

    Map集合介绍
    image.png
    HashMap: 线程不安全,效率高,能够存储null的key和value。
    LinkedHashMap: HashMap的子类,他能保证遍历出来的元素是插入的顺序。底层通过链表拼接。
    HashTable:老的哈希表。被HashMap替换。 线程安全的,效率低。和Vector一样。不能存储null的key和value。
    TreeMap:底层通过红黑树实现的Map。遍历出来按照key排序。
    properties: 继承了TreeMap,常用来配置文件。

    LinkedHashMap底层维护了一个链表,如果我们Map需要边插入边遍历,我们就可以使用这个容器。提升性能。

    JDK7和JDK8哈希表之间的区别?

    1. jdk7底层是通过数组+链表的形式实现, jdk8通过数组+链表+红黑树实现。
    2. new HashMap,底层是不会创建长度为16的数组的,只有第一次插入put元素才会创建长度。
    3. 默认的长度为16。加载因子(长度阈值):0.75。
    4. jdk7使用Entry, jdk8使用Node。

    而LinkedHashMap继承了HashMap, 对于存储的元素来说是链表,而不是元素本身。

    Map常用方法:
    image.png
    元视图方法:

    1. 通过 keySet 可以获取所有key值
    2. 通过 values 获取所有的value值
    3. 通过 entrySet 获取所有的key-value值。

      Set objects = map.keySet();
      System.out.println(objects);

      Collection values = map.values();
      System.out.println(values);

      Set> entries = map.entrySet();
      for (Map.Entry entry : entries) {
      System.out.println(entry.getKey() + “__” + entry.getValue());
      }

      对于TreeMap来说,如果想要使用排序,就必须要实现自定义对象的比较规则。比较器。
      对于HashTable来说,已经不再使用了,但对于它的继承类Properties来说,还是有用处的。

      Properties(配置)extends HashTable:

      properties常用来配置文件,key和value都是String类型。
      例如下面的情况

      prop.driverClass=com.mysql.jdbc.Driver
      prop.url=jdbc:mysql://localhost:3306/testmysql
      prop.username=root
      prop.password=123456

      Collections工具类

      Collection和Collections的区别?(面试)
      Collection是接口, List和Set都继承它, 而Collections是操作Map、Set、List的工具类。

      1. Collections是操作List、Set、Map的工具类。
      2. Collections是里面提供静态方法。

      image.png
      28、泛型

      允许定义在类、接口时通过一个标识表示类中某个属性的类型或者返回值或参数类型。
      泛型不能是基础类型。 也必须时包装类。
      泛型是在JDK5后面提供的。

      1. 泛型类可以定义多个参数
      2. 虽然有ArrayList和ArrayList,但是运行时ArrayList只有一个。
      3. 泛型当中不能使用基础数据类型,必须使用类对象。
      4. 泛型对象只能赋值。因为可能不一样。
      5. 不能在静态方法中,使用泛型类型,因为泛型类型是在实例化对象(运行阶段)的时候确认的。
      6. 子类可能不继承父类的泛型,也可以继承一部分,也可以全部不继承。还可以在保留的继承增加,或者在自己的基础上增加新的。
      7. 如果方法或者属性中使用了类的泛型,则不能声明为static,因为不确定类型,泛型是在初始化对象确定的。
      8. 当存在泛型之后,类的类型就不再是类了,而是类+泛型。 编译不通过。
      9. 泛型没有继承传递性。

      1)泛型方法:
      在方法当中出现了泛型结构,但是方法中的泛型参数与类的泛型无关。也就是说泛型方法所属的类是不是泛型没有关系。

      泛型方法中的泛型不同于类中的泛型,方法中的泛型取决于调用者传入的参数,而跟类本身没有关系,因此泛型方法可以声明为static静态方法。

      可以使用一个泛型类对象Base, 然后实现各种各样的类继承Base,传递参数。 class Consumer extends Base,保证Consumer的对象调用Base方法都是确定类型的。 进而容易扩充类型。

      2)通配符
      我们都知道,当有泛型之后,类的类型就是类+泛型。形如下面这种新式就不能通过。
      List list1 = new ArrayList<>();
      List list2 = new ArrayList<>();
      list1 = list2; // error
      因此解决上面的问题,我们使用List<?> list =list1 / list2来解决适配问题。
      类A是类B的父类, G与G也是没有关系的,两者共同的父类是G<?>。

      1. List<?> list, list不能添加add任何数据,但是可以添加null
      2. list可以读,但是数据为Object类型。

      有限制的通配符:

      ? extends Person ? super Person

      1. // 这个可以接收所有继承DAO的对象引用
      2. List<? extends DAO> list1 = null;
      3. // 这个可以接收所有被DAO继承的对象引用
      4. List<? super DAO> list = null;
      5. List<ConsumerDAO> list2 = null;
      6. List<Object> list3 = null;
      7. List<DAO> list4 = null;
      8. list1 = list2;
      9. list1 = list4;
      10. // <? extends DAO> 相当于 [?, DAO]
      11. // <? super DAO> 相当于 (DAO, ?]
      12. // 对于<? extends DAO>来说,get使用DAO对象接收。也可以使用Object接收
      13. DAO dao1 = list1.get(0);
      14. // 对于<? super DAO>来说,同样相同的道理
      15. // 对于插入来说, list1是不能插入任何数据的。
      16. // list来说,可以插入DAO,继承DAO的所有数据。

      29、文件操作

      背景:数据持久化,将内存和磁盘上的数据交互以及存储。

      1)File类使用

      一个file类代表一个文件,或者文件夹。

      // 相对路径在当前项目的filTest路径下
      
      File file = new File("E:/hello.txt");
      System.out.println(file);
      

      window下路径分隔符默认使用: \
      Linux和Unix默认使用:/
      Java提供了File.separator自动识别
      此时还不算是操作文件,只是创建了对象。

      File常用的方法:
      image.png
      image.png
      File类相当于文件的管理和查询, 而不是写入或读入文件内容。

      2)IO流

      把数据存放到磁盘上,使用输入Input流,把磁盘上的数据读到内存,使用输出Output流。
      IO流分为字节流InputStream/OutputStream和字符流Reader/Writer。
      image.png
      image.png

          public static void main(String[] args) throws IOException {
              // 相对路径在当前项目的filTest路径下
              File file = new File("E:/hello.txt");
              // 这个可能会抛出空文件异常 NotFoundFileException
              FileReader reader = new FileReader(file);
              // 读取一个字符, 如果到了文件结尾则会返回-1
              int read = reader.read();
              while (read != -1) {
                  System.out.println((char)read);
                  read = reader.read();
              }
              reader.close();
          }
      
          // 搭配数组进行文件读取。
          public static void main(String[] args) throws IOException {
              // 相对路径在当前项目的filTest路径下
              File file = new File("E:/hello.txt");
              FileReader reader = new FileReader(file);
              // 读取一个字符, 如果到了文件结尾则会退出
              char[] buffer = new char[5];
              int read = -1;
              while ((read = reader.read(buffer)) != -1) {
                  for (int i = 0; i < read; i++) {
                      System.out.print(buffer[i]);
                  }
                  String str = new String(buffer, 0, read);
                  System.out.println(str);
              }
          }
      

      数据写入

              File file = new File("E:\\hello1.txt");
              FileWriter writer = new FileWriter(file);
              // write若没有文件,则会创建新的
              // 默认覆盖原有文件内容
              // FileWrite(file, true) 则追加内容
              writer.write("heheh\n");
              writer.write("呵呵");
              writer.close();
      

      字符流不能处理图片,只能通过字节流。

          public static void main(String[] args) throws IOException {
              File readerFile = new File("E:\\tt.jpg");
              File writerFile = new File("E:\\hello1.jpg");
      
              FileInputStream fileInputStreamReader = new FileInputStream(readerFile);
              FileOutputStream fileOutputStreamWriter = new FileOutputStream(writerFile);
              byte[] buffer = new byte[1024];
              int readSize = 0;
              while ((readSize = fileInputStreamReader.read(buffer)) != -1) {
                  fileOutputStreamWriter.write(buffer, 0, readSize);
              }
              fileInputStreamReader.close();
              fileOutputStreamWriter.close();
          }
      

      对于文本文件(.txt, .java, .c, .cpp) 使用字符流处理 对于非文本文件(.jpg, .mp3, .mp4, .avi, .doc, .ppt) 使用字节流处理

      缓冲流:
      对于上面的流处理,我们基本不使用,因为上面的流处理太过慢,后续使用缓冲流。缓冲流的目的就是为了提高读写效率。

      BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter

          public static void main(String[] args) throws IOException {
              File readerFile = new File("E:\\tt.jpg");
              File writerFile = new File("E:\\hello1.jpg");
      
              FileInputStream fileInputStreamReader = new FileInputStream(readerFile);
              FileOutputStream fileOutputStreamWriter = new FileOutputStream(writerFile);
              // 缓冲区需要使用输入输出流支持
              BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStreamReader);
              BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStreamWriter);
      
              byte[] buffer = new byte[1024];
              int readSize = 0;
              while ((readSize = bufferedInputStream.read(buffer)) != -1) {
                  bufferedOutputStream.write(buffer, 0, readSize);
              }
              // 关闭外层,会自动关闭内层
              bufferedInputStream.close();
              bufferedOutputStream.close();
          }
      
          public static void main(String[] args) throws IOException {
              File readerFile = new File("E:\\hello.txt");
              File writerFile = new File("E:\\hello1.txt");
      
              FileReader fileReader = new FileReader(readerFile);
              FileWriter fileWriter = new FileWriter(writerFile);
      
              BufferedReader bufferedReader = new BufferedReader(fileReader);
              BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
              char[] buffer = new char[1024];
              int readSize = 0;
              while((readSize = bufferedReader.read(buffer)) != -1) {
                  bufferedWriter.write(buffer, 0, readSize);
              }
              bufferedReader.close();
              bufferedWriter.close();
          }
      

      对于缓冲流来说, 新增了一个flush刷新功能, 直接将已经缓存的数据刷新。

      转换流:提供了字节流和字符流之间的转换。
      image.png
      InputStreamReader以字节流读取内容,转化为字符流处理, 同理写进入的数据为字符流数据,被转化为字节流存储到磁盘中。
      将字节、字节数组 转化为 字符、字符数组称为解码过程
      将字符、字符数组转化为字节、字节数组为编码过程。

          public static void main(String[] args) throws IOException {
              File readerFile = new File("E:\\hello.txt");
              File writerFile = new File("E:\\hello1.txt");
      
              FileInputStream fileInputStream = new FileInputStream(readerFile);
              FileOutputStream fileOutputStream = new FileOutputStream(writerFile);
              // 可以设置读取的格式
              InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "utf-8");
              // 可以设置写入的格式
              OutputStreamWriter outputStreamWriter = new OutputStreamWriter(fileOutputStream, "gbk");
      
              char[] buffer = new char[1024];
              int readSize = 0;
              while ((readSize = inputStreamReader.read(buffer)) != -1) {
                  outputStreamWriter.write(buffer, 0, readSize);
              }
              inputStreamReader.close();
              outputStreamWriter.close();
          }
      

      输入输出流:

      System.in 标准输入流,默认从键盘上输入 System.out 控制台输出

          public static void main(String[] args) throws IOException {
              InputStreamReader inputStreamReader = new InputStreamReader(System.in);
              BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
      
              while (true) {
                  String data = bufferedReader.readLine();
                  System.out.println(data);
                  if ("e".equalsIgnoreCase(data) || "exit".equalsIgnoreCase(data)) {
                      break;
                  }
              }
      

      打印流:使用System.serOut()设置输出文件

      PrintStream PrintWriter

      image.png
      数据流:为了方便操作Java语言的基本数据类型和String类型,可以使用数据流。

      DataInputStream DataOutputStream

      可以写入各种各样的Java支持的数据类型。

      对象类:用于存储和读取基本数据类型数据或者对象的数据流。可以将Java对象读入到内存中,又可以将Java中对象写入文件中。
      image.png
      对象的序列化机制: 将对象转化为与平台无关的二进制流,在接受到之后反序列恢复为原来的对象数据。
      对于对象的序列化和反序列化,需要继承Serializble接口。

          public static void main(String[] args) throws IOException, ClassNotFoundException {
              ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("E:\\hao.txt"));
              objectOutputStream.writeObject(new String("阿斯利康的话就考虑进来看见发"));
              objectOutputStream.flush();
      
              ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("E:\\hao.txt"));
              Object object = objectInputStream.readObject();
              System.out.println((String)object);
          }
      

      随机流:RandomAccessFile 可以实现任意位置的写文件和任意位置读文件。

      NO2提供的File类的升级版-Path
      image.png
      Commons提供的文件开源包 - FileUtils