自用的快速复习Java基础知识,不适用于每一个人

自用的快速复习java基础知识,不适用于每一个人

  • 问题背景
          • 1. 类定义出来的变量称为**对象** [IDEA安装](https://www.jb51.net/article/193853.htm) [IDEA破解](https://www.jb51.net/article/197138.htm) [破解2](http://blog.haoservice.cn/archives/6501)
          • 2. Java创建对象
          • 3. 类中成员的称呼 类的运行顺序
          • 4. OOP的含义
          • [5. JVM(Java Virtual Machine)虚拟机](http://www.weixueyuan.net/view/6309.html)
          • 6. Java两种数组定义方式
          • 7. StringBuffer字符串拼接
          • 8. 简易版 for 循环
          • 9. 二维数组
          • 10. new String()两次内存创建 StingBuffer
        • 11. String、StringBuffer和StringBuild的区别和共同点
          • 12. String字符串相同,使用==判断为假
          • 13. public:共有的
          • 14. protected:受保护的
          • 15. private:私有的
          • 16. 默认的:不使用任何关键字
          • 17. 访问控制和继承
          • 18. 访问控制符可以控制代码的权限
          • 19. [this关键字](http://www.weixueyuan.net/view/5988.html)
          • 20. this和构造函数的调用顺序
          • 21. Java方法重载(method overloading)
          • 22. Java覆盖(重写) override 与重载的区别
          • 23. [Java包装类、拆箱和装箱](http://www.weixueyuan.net/view/5990.html)
          • 24. [Java包](http://www.weixueyuan.net/view/6319.html)
          • 25. Java源文件的声明规则   一个源文件中定义多个类,还有 import 和 package 语句
          • 26. Java继承
          • 27. [Java多态](http://www.weixueyuan.net/view/6000.html)
          • 28. [Java动态绑定调用流程](http://www.weixueyuan.net/view/6000.html)
          • 29. static关键字以及静态变量、静态方法和静态初始器(静态块)
          • 30. Java final关键字:阻止继承和多态
          • 31. Object类
          • 32. Object类 equals() 方法
          • 33. Object类 hashCode() 方法
          • 34. Object类 toString() 方法
          • 35. [内部类](http://www.weixueyuan.net/view/6006.html)
          • 36. Java抽象类的概念和使用
          • 37. Java接口(interface)
          • 38. Java接口和抽象类的区别
          • 39. Java异常
          • 40. Java内置异常
          • 41. 断言
        • 42. Java线程
          • 43. 基本类型与引用类型
          • 44. 浅拷贝与深拷贝
          • 45. mysql连接乱码解决
          • 46. 数据库连接池
          • 47. equal 和 ==
          • 48. ArrayList 内存结构
  • Lyric: 它在灌木丛旁邂逅

问题背景

自用的快速复习java基础知识,不适用于每一个人

1. 类定义出来的变量称为对象 IDEA安装 IDEA破解 破解2
  • 该看书籍
  • Integer的equals重写过,比较的是值是否相等;==比较对象是否相等
  • Java 是一种强类型的语言,声明变量时必须指明数据类型。变量(variable)的值占据一定的内存空间。不同类型的变量占据不同的大小。
  • 不像 C/C++,Java 不支持无符号类型(unsigned)。
  • 类必须先定义才能使用。类是创建对象的模板,创建对象也叫类的实例化。
  • 构造方法的名称必须与类的名称相同,并且没有返回值。
  • 通常情况下,K 表示键,V 表示值,E 表示异常或错误,T 表示一般意义上的数据类型

T 代表 Type,表示任意的一个java类型。
E 代表 Element 的意思,或者 Exception 异常的意思,在集合中比较常见。
K 代表 Key 的意思,通常与 V 一起使用,通常用Map中比较常见。
V 代表 Value 的意思,通常与 K 一起配合使用,通常用Map中比较常见。
?代表 不确定的java类型。
S 和 U 基本上与 T 相同,即表示任意的一个Java类型。

  • 每个类都有构造方法。如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认的构造方法。
  • 枚举看作特殊的类,注解看作特殊的接口,把注解当成标签,方便区分。
  • public @interface MyAnnotation,里面的方法叫成员变量,不叫方法。
  • 在类实例化的过程中自动执行的方法叫做构造方法,不需要手动调用。构造方法可以在类实例化的过程中做一些初始化的工作。
  • 方法进入时,应该进行参数校验。
  • 一个类可以包含以下类型变量:
    >  局部变量:在方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。形参的作用域是整个方法体,是局部变量。
    >  成员变量:成员变量是定义在类中、方法体之外的变量。这种变量在创建对象的时候实例化(分配内存)。成员变量可以被类中的方法和特定类的语句访问。
    >  类变量:类变量也声明在类中,方法体之外,但必须声明为static类型
  • 在Java中,变量的作用域分为四个级别:类级、对象实例级、方法级、块级:
    >  类级变量又称全局级变量或静态变量,需要使用static关键字修饰。类级变量在类定义后就已经存在,占用内存空间,可以通过类名来访问,不需要实例化。
    >  对象实例级变量就是成员变量,实例化后才会分配内存空间,才能访问。
    >  方法级变量就是在方法内部定义的变量,就是局部变量。
    >  块级变量就是定义在一个块内部的变量,变量的生存周期就是这个块,出了这个块就消失了,比如 if、for 语句的块,块是指由大括号包围的代码。
    >  方法内部除了能访问方法级的变量,还可以访问类级和实例级的变量。
    >  块内部能够访问类级、实例级变量,如果块被包含在方法内部,它还可以访问方法级的变量。
    >  方法级和块级的变量必须被显示地初始化,否则不能访问。
2. Java创建对象
  • 在C语言中,通过结构体名称就可以完成结构体变量的定义,并分配内存空间;在Java中,通过类来定义变量不会分配内存空间,必须使用new关键字来完成内存空间的分配。在Java中,通过类使用new关键字来创建对象。
  • 使用new关键字来创建对象,一般有以下三个步骤:
    >  声 明:声明一个对象,包括对象名称和对象类型。
    >  实例化:使用关键字new来创建一个对象。
    >  初始化:使用new创建对象时,会调用构造方法初始化对象。
Student s = new Student();  // 必须使用new关键字
3. 类中成员的称呼 类的运行顺序
  • 类所包含的变量和函数都有特定的称呼,变量被称为属性(通常也称成员变量),函数被称为方法,属性和方法统称为类的成员。
  • 以 com.* 开头的包往往由盈利性的公司发布,可能会有版权问题,使用时要注意。
  • Java类的基本运行顺序
4. OOP的含义
  • 面向对象编程(Object Oriented Programming, OOP),Java、C++支持类和对象,称为面向对象编程。C语言不支持类和对象的概念,称为面向过程的编程语言。
  • 面向对象编程在软件执行效率上绝对没有任何优势,它的主要目的是方便程序员组织和管理代码,快速梳理编程思路,带来编程思想上的革新。
  • API(Application Programming Interface, 应用程序编程接口)是一个通用概念。
5. JVM(Java Virtual Machine)虚拟机
  • Java源码编译后会生成一种 .class 文件,称为字节码文件。Java虚拟机就是负责将字节码文件翻译成特定平台下的机器码然后运行。只要在不同平台上安装对应的JVM,就可以运行字节码文件,实现跨平台。
  • JVM是一个”桥梁“,是一个”中间件“,是实现跨平台的关键,Java代码首先被编译成字节码文件,再由JVM将字节码文件翻译成机器语言,从而达到运行Java程序的目的。
  • 编译的结果不是生成机器码,而是生成字节码,字节码不能直接运行,必须通过JVM翻译成机器码才能运行。不同平台下编译生成的字节码是一样的,但是由JVM翻译成的机器码却不一样。
  • 跨平台的是Java程序,不是JVM。JVM是用C/C++开发的,是编译后的机器码,不能跨平台,不同平台下需要安装不同版本的JVM。
6. Java两种数组定义方式
  • type arrayName[];  int demoArray[];  int demoArray[] = new int[3];
  • type[] arrayName;  int[] demoArray;  int[] demoArray = new int[3];
7. StringBuffer字符串拼接
  • 字符串可以通过“+”连接,基本数据类型与字符串进行“+”操作一般也会自动转换为字符串。
  • 在循环和多个表达式中不能 +,频繁创建 StringBuffer 性能影响。
  • 在单个表达式中可以用 +,编译器直接做了优化。如 String str = “www.” + “javastack.” + “com”;
String str = "Hello ";
str += "World!";

  运行原理:程序首先产生了str1字符串,并在内存中申请了一段空间。此时要追加新的字符串是不可能的,因为字符串被初始化后,长度是固定的。如果要改变它,只有放弃原来的空间,重新申请能够容纳“Hello World!”字符串的内存空间,然后将“Hello World!”字符串放到内存中。

8. 简易版 for 循环
int arrayDemo[] = {1, 2, 4, 7, 9, 192, 100};
for(int x: arrayDemo){
    System.out.println(x + ", ");     // 无法使用数组索引
}
9. 二维数组
  • Java语言中,把二维数组看作是数组的数组,数组空间不是连续分配的。
  • 静态数组一旦被声明,它的容量就固定了,不容改变。所以在声明数组时,一定要考虑数组的最大容量,防止容量不够的现象。
  • 如果想在运行程序时改变容量,就需要用到数组列表(ArrayList,也称动态数组)或向量(Vector)。
  • 由于静态数组容量固定的缺点,实际开发中使用频率不高,被 ArrayList 或 Vector 代替,因为实际开发中经常需要向数组中添加或删除元素,而它的容量不好预估。
int intArray[ ][ ] = { {1,2}, {2,3}, {4,5} };   // 3行2列
int a[ ][ ] = new int[2][3];  // 2行3列
10. new String()两次内存创建 StingBuffer
  • String str = new String(“abc”); 实际上创建了两个String对象,一个是”abc”对象,存储在常量空间中,一个是使用new关键字为对象str申请的空间,所以内存消耗比较大。
  • 使用简单式创建 String str = “abc”;
  • String 的值是不可变的,每次对String的操作都会生成新的String对象,不仅效率低,而且耗费大量内存空间,StringBuffer效率更高。
  • StringBuffer类和String类一样,也用来表示字符串,但是StringBuffer的内部实现方式和String不同,在进行字符串处理时,不生成新的对象,在内存使用上要优于String。
  • StringBuffer 默认分配16字节长度的缓冲区,当字符串超过该大小时,会自动增加缓冲区长度,而不是生成新的对象。
11. String、StringBuffer和StringBuild的区别和共同点
  • StringBuilder类和StringBuffer类功能基本相似,方法也差不多,主要区别在于StringBuffer类的方法是多线程安全的,而StringBuilder不是线程安全的,StringBuilder类会略微快一点。
  • StringBuffer、StringBuilder、String中都实现了CharSequence接口。
  • 一般情况下,速度从快到慢为 StringBuilder > StringBuffer > String,这是相对的,不是绝对的。
  • 操作少量的数据使用 String;单线程操作大量数据使用 StringBuilder;多线程操作大量数据使用 StringBuffer。
12. String字符串相同,使用==判断为假
String a = new String("test");   
boolean res = ( a == "test" );   // 输出false
  • 因为a指向的对象不是"test",而是另一个String对象。尽管两个对象的内容相同,由于==判断的是两个对象是否是同一个对象,故得到的结果是false。
  • 判断两个字符串的内容是否相等时,应该用 a.equals(“test”) 这个函数。
13. public:共有的
  • 被声明为public的类、方法、构造方法和接口能够被任何其他类访问。
  • 如果几个相互访问的 public 类分布在不用的包中,则需要导入相应public类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。
  • Java程序的main() 方法必须设置成公有的,否则,Java解释器将不能运行该类。
14. protected:受保护的
  • 被声明为protected的变量、方法和构造方法能被同一个包中的任何其他类访问,也能够被不同包中的子类(派生类)访问。
  • 只想让该方法对其所在类的子类(派生类)可见,则将该方法声明为protected
  • protected访问修饰符不能修饰类和接口,方法和成员变量能够声明为protected,但是接口的成员变量和成员方法不能声明为protected。
  • 子类能访问protected修饰符声明的方法和变量,这样就能保护不相关的类使用这些方法和变量。
15. private:私有的
  • 私有访问修饰符是最严格的访问级别,被声明为private的方法、变量和构造方法只能被所属类访问,并且类和接口不能声明为private。
  • 声明为私有访问类型的变量只能通过类中公共的Getter/Setter方法被外部类访问。
  • private访问修饰符的使用主要用来隐藏类的实现细节和保护类的数据。
16. 默认的:不使用任何关键字
  • 在同一包内可见,默认不使用任何修饰符。
  • 不使用任何修饰符声明的属性和方法,对同一个包内的类是可见的。
  • 接口里的变量都隐式声明为public static final,而接口里的方法默认情况下访问权限为public。
17. 访问控制和继承
  • 父类(基类)中声明为 public 的方法在子类(派生类)中也必须为public。
  • 父类(基类)中声明为 protected 的方法在子类(派生类)中要么声明为protected,要么声明为public。不能声明为private。
  • 父类(基类)中默认修饰符声明的方法,能够在子类(派生类)中声明为private。
  • 父类(基类)中声明为private的方法,不能够被继承。
18. 访问控制符可以控制代码的权限
  • 当需要让自己编写的类被所有的其他类访问时,就可以将类的访问控制符声明为 public。
  • 当需要让自己的类只能被自己的包中的类访问时,就可以省略访问控制符。
  • 当需要控制一个类中的成员数据时,可以将这个类中的成员数据访问控制符设置为 public、protected,或者省略。
19. this关键字
  • this 关键字用来表示当前对象本身,或当前类的一个实例,通过 this 可以调用本对象的所有方法和属性。
  • 成员变量与方法内部的变量重名时,使用 this 区分。
  • 在构造方法中调用另一个构造方法,调用动作必须置于最起始的位置。
  • 不能在构造方法以外的任何方法内调用构造方法。
  • 在一个构造方法内只能调用一个构造方法。
20. this和构造函数的调用顺序
public class javaTest01{
    public static void main(String[] args){
    //    B b = new B(new A());    // 这一条和下面两条是等价的
        A a = new A();     // 实例化,上面一条先调用 new A() 的构造函数 
        B b = new B(a);   // 上面一条完全结束后,这条再调用 B 类的构造函数
    }
}

class A{
    public A(){
        System.out.println("先调用A构造函数");   //  进入 A 的构造函数,打印这条语句
        new B(this).print();  // 匿名对象就是没有名字的对象,new B(this)看做(new B(aaa))
                              // 所以先调用 B 的构造函数,打印 "先调用 B 构造函数",再调用B类的print()函数
    }
    public void print(){
        System.out.println("Hello from A!");
    }
}

class B{
    A a;  // 声明
    public B(A aaa){
        System.out.println("先调用B构造函数");
        this.a = aaa;
    }
    public void print() {
        a.print();  // 调用 A 类中的 print() 方法
        System.out.println("Hello from B!");
    }
}

先调用A构造函数
先调用B构造函数
Hello from A!
Hello from B!
先调用B构造函数

21. Java方法重载(method overloading)
  • 同一个类中的多个方法可以有相同的名字,只要它们的参数列表不同就可以,这被称为方法重载。
  • 参数列表又叫参数签名,包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同。
  • 重载是面向对象的一个基本特性。
  • 重载就是在一个类中,有相同的函数名称,但形参不同的函数。重载的结果,可以让一个程序段尽量减少代码和方法的种类。
  • 参数列表不同包括:个数不同、类型不同和顺序不同。
  • 仅仅参数变量名称不同是不可以的。
  • 跟成员方法一样,构造方法也可以重载。
  • 声明为 final 的方法不能被重载。
  • 声明为static的方法不能被重载,但是能够被再次声明。
  • 方法的重载的规则:
    >  方法名称必须相同。
    >  参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等)。
    >  方法的返回类型可以相同也可以不相同。
    >  仅仅返回类型不同不足以成为方法的重载。
  • 方法重载的实现:方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错,这叫做重载分辨。
22. Java覆盖(重写) override 与重载的区别
  • 在新类中定义一个方法,其名称、返回值类型和参数列表与父类中的相同,新方法被称做覆盖旧方法。
  • 参数列表又叫参数签名,包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同。
  • 被覆盖的方法在子类中只能通过 super 调用。
  • 覆盖不会删除父类中的方法,而是对子类的实例隐藏,暂时不使用。
  • 方法覆盖的原则:
    >   覆盖方法的返回类型、方法名称、参数列表必须与原方法的相同。
    >   覆盖方法不能比原方法访问性差(即访问权限不允许缩小)。
    >   覆盖方法不能比原方法抛出更多的异常。
    >   被覆盖的方法不能是 final 类型,因为 final 修饰的方法是无法覆盖的。
    >   被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
    >   被覆盖的方法不能为static。如果父类中的方法为静态的,而子类中的方法不是静态的,但是两个方法除了这一点外其他都满足覆盖条件,那么会发生编译错误;反之亦然。即使父类和子类中的方法都是静态的,并且满足覆盖条件,但是仍然不会发生覆盖,因为静态方法是在编译的时候把静态方法和类的引用类型进行匹配。
  • 覆盖和重载的不同:
    >   方法覆盖要求参数列表必须一致,而方法重载要求参数列表必须不一致。
    >   方法覆盖要求返回类型必须一致,方法重载对此没有要求。
    >   方法覆盖只能用于子类覆盖父类的方法,方法重载用于同一个类中的所有方法(包括从父类中继承而来的方法)。
    >   方法覆盖对方法的访问权限和抛出的异常有特殊的要求,而方法重载在这方面没有任何限制。
    >   父类的一个方法只能被子类覆盖一次,而一个方法可以在所有的类中可以被重载多次。
23. Java包装类、拆箱和装箱
  • byte、boolean、char、short、int、long、float、double,这八种基本数据类型并不支持面向对象编程。
  • 基本类型的数据不具备“对象”的特性——不携带属性、没有方法可调用。
  • Java为每种基本数据类型分别设计了对应的类,称为包装类(Wrapper Classes),也称为外覆类或数据类型类。Byte、Boolean、Character、Short、Integer、Long、Float、Double。
  • 基本类型和对应的包装类可以相互装换。
  • 由基本类型向对应的包装类转换称为装箱,例如把 int 包装成 Integer 类的对象。
  • 包装类向对应的基本类型转换称为拆箱,例如把 Integer 类的对象重新简化为 int。
  • Java 1.5(5.0) 之前必须手动拆箱装箱。Java 1.5 之后可以自动拆箱装箱,也就是在进行基本数据类型和对应的包装类转换时,系统将自动进行方便程序员的代码书写。
24. Java包
  • 在Java中,为了组织代码的方便,可以将功能相似的类放到一个文件夹内,这个文件夹,就叫做包。
  • 包不但可以包含类,还可以包含接口和其他的包。
  • 包以"."来表示层级关系,例如 p1.p2.Test 表示的目录为 \p1\p2\Test.class。
  • java 命令与 javac 命令的区别,执行 javac 命令需要进入当前目录,而执行 java 命令需要进入当前目录的上级目录,并且类名前面要带上包名。
  • javac是一个平台命令,它对具体的平台文件进行操作,要指明被编译的文件路径。
  • java是一个虚拟机命令,它对类操作,对类的描述要用点分的描述形式,并且不能加扩展名,还要注意类名的大小写。
  • 实际开发都借助 IDEA 或者 Eclipse 工具等,去管理包、编译运行程序,工具实际上也是执行这些命令。
  • 被声明为 public 的类、方法或成员变量,可以被任何包下的任何类使用。
  • 被声明为 private 的类、方法或成员变量,只能被本类使用。
  • 没有任何修饰符的类、方法和成员变量,只能被本包中的所有类访问,在包以外任何类都无法访问它。
25. Java源文件的声明规则   一个源文件中定义多个类,还有 import 和 package 语句
  • 一个源文件中只能有一个public类。
  • 一个源文件可以有多个非public类。
  • 源文件的名称应该和public类的类名保持一致。例如:源文件中public类的类名是Employee,那么源文件应该命名为Employee.java。
  • 如果一个类定义在某个包中,那么package语句应该在源文件的首行
  • 如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
  • import语句和 package 语句对源文件中定义的所有类都有效。
  • 在同一源文件中,不能给不同的类不同的包声明。
  • 类有若干种访问级别,并且类也分不同的类型:抽象类和 final 类等。还有一些特殊的类,如内部类、匿名类。
26. Java继承
  • 继承可以理为一个类从另一个类获取方法和属性的过程。如果类B继承于类A,那么B就拥有A的方法和属性。
  • 继承使用 extends 关键字。
  • 子类可以覆盖父类的方法。
  • 子类可以继承父类除private以为的所有的成员。
  • 构造方法不能被继承
  • 一个类能得到构造方法,只有两个办法:编写构造方法,或者根本没有构造方法,类有一个默认的构造方法。
  • super 关键字与 this 类似,this 用来表示当前类的实例,super 用来表示父类。
  • super 也可以用在子类的子类中,Java 能自动向上层类追溯。
  • super 关键字的功能:
    >  调用父类中声明为 private 的变量。
    >  点取已经覆盖了的方法。
    >  作为方法名表示父类构造方法。
  • 在构造方法中调用另一个构造方法,调用动作必须置于最起始的位置。
  • 不能在构造方法以外的任何方法内调用构造方法。
  • 在一个构造方法内只能调用一个构造方法。
  • 无论是 super() 还是 this(),都必须放在构造方法的第一行。
  • 如果编写一个构造方法,既没有调用 super() 也没有调用 this(),编译器会自动插入一个调用到父类构造方法中,而且不带参数。
  • super 与 this 的区别:super 不是一个对象的引用,不能将 super 赋值给另一个对象变量,它只是一个指示编译器调用父类方法的特殊关键字。
27. Java多态
  • 在Java中,父类的变量(父类声明的对象)可以引用父类的实例(方法),也可以引用子类的实例(方法)。
  • 对象既可以是人类,也可以是猫、狗,它有不同的表现形式,这就被称为多态。多态是指一个事物有不同的表现形式或形态。
  • 多态存在的三个必要条件:要有继承、要有重写、父类变量引用子类对象。
  • 在继承链中,我们将子类向父类转换称为向上转型,将父类向子类转换称为向下转型
  • 不能直接将父类的对象强制转换为子类类型,只能将向上转型后的子类对象再次转换为子类类型。也就是说,子类对象必须向上转型后,才能再向下转型。
  • 对象的类型转换在程序运行时检查,向上转型会自动进行,向下转型的对象必须是当前引用类型的子类。
28. Java动态绑定调用流程
  • (1) 编译器查看对象的声明类型和方法名。
    >  假设调用 obj.func(param),obj 为 Cat 类的对象。可能存在多个名字为func但参数签名不一样的方法。
    >  例如,可能存在重载方法 func(int) 和 func(String)。编译器将会一一列举所有 Cat 类中名为func的方法和其父类 Animal 中访问属性为 public 且名为func的方法。
    >  然后编译器获得了所有可能被调用的候选方法列表
  • (2) 编译器将检查调用方法时提供的参数签名(参数列表)。
    >  如果在所有名为func的方法中存在一个与提供的参数签名完全匹配的方法,那么就选择这个方法。这个过程被称为重载解析(overloading resolution)。
    >  例如,如果调用 func(“hello”),编译器会选择 func(String),而不是 func(int)。
    >  由于自动类型转换的存在,例如 int 可以转换为 double,如果没有找到与调用方法参数签名相同的方法,就进行类型转换后再继续查找,如果最终没有匹配的类型或者有多个方法与之匹配,那么编译错误。
    >  然后编译器获得了需要调用的方法名字和参数签名(参数列表)。
  • (3) 如果方法的修饰符是private、static、final,或者是构造方法,编译器可以准确地知道应该调用哪个方法,这种调用方式 称为静态绑定(static binding)。
    >  调用的方法依赖于对象的实际类型, 并在运行时实现动态绑。例如调用 func(“hello”),编泽器将采用动态绑定的方式生成一条调用 func(String) 的指令。
  • (4) 当程序运行,并且釆用动态绑定调用方法时,JVM一定会调用与 obj 所引用对象的实际类型最合适的那个类的方法。
    >  假设 obj 的实际类型是 Cat,它是 Animal 的子类,如果 Cat 中定义了 func(String),就调用它,否则将在 Animal 类及其父类中寻找。
    >  每次调用方法都要进行搜索,时间开销相当大,因此,JVM预先为每个类创建了一个方法表(method lable),其中列出了所有方法的名称、参数签名和所属的类。
    >  在真正调用方法的时候,虚拟机只需要查找这个方法表就行了。
    >  如果调用super.func(“hello”),编译器将直接对父类的方法表进行搜索。
    >  实际上,Animal 也有默认的父类 Object,会继承 Object 的方法。
  • (5) 在运行的时候,调用 obj.cry() 方法的过程如下:
    >  JVM 首先访问 obj 的实际类型的方法表,可能是 Animal 类的方法表,也可能是 Cat 类及其子类的方法表。
    >  JVM 在方法表中搜索与 cry() 匹配的方法,找到后,就知道它属于哪个类了。
    >  JVM 调用该方法。
29. static关键字以及静态变量、静态方法和静态初始器(静态块)
  • static 修饰符能够与变量、方法一起使用,表示是静态的。
  • 静态变量和静态方法能够通过类名来访问,不需要创建一个类的对象来访问该类的静态成员,所以static修饰的成员又称作类变量和类方法。
  • 静态变量与实例变量不同,实例变量总是通过对象来访问,因为它们的值在对象和对象之间有所不同,而静态变量是相同的。
  • 静态变量属于类,不属于任何独立的对象,所以无需创建类的实例就可以访问静态变量。
  • 之所以会产生上一条的结果,是因为编译器只为整个类创建了一个静态变量的副本,也就是只分配一个内存空间,虽然有多个实例,但这些实例共享该内存。
  • 实例变量则不同,每创建一个对象,都会分配一次内存空间,不同变量的内存相互独立,互不影响,改变 a 对象的实例变量不会影响 b 对象。
  • 静态变量虽然也可以通过对象来访问,但是不被提倡,编译器也会产生警告。
  • static 的变量是在类装载的时候就会被初始化。只要类被装载,不管你是否使用了这个static 变量,它都会被初始化。
  • 类变量(class variables)用关键字 static 修饰,在类加载的时候,分配类变量的内存,以后再生成类的实例对象时,将共享这块内存(类变量),任何一个对象对类变量的修改,都会影响其它对象。
  • 外部有两种访问静态变量的方式:通过对象来访问或通过类名来访问。
  • 静态方法是一种不能向对象实施操作的方法。例如,Math 类的 pow() 方法就是一个静态方法,语法为 Math.pow(x, a),用来计算 x 的 a 次幂,在使用时无需创建任何 Math 对象。
  • 因为静态方法不能操作对象,所以不能在静态方法中访问实例变量,只能访问自身类的静态变量。
  • 两种情况可以使用静态方法:
    >   一是不需要访问对象状态,其所需参数都是通过显式参数提供(例如 Math.pow(x, a))。
    >   二是方法只需要访问类的静态变量。
  • main()也是一个静态方法,不对任何对象进行操作。实际上,在程序启动时还没有任何对象,main() 方法是程序的入口,将被执行并创建程序所需的对象。
  • 静态变量和静态方法的总结:
    >   一个类的静态方法只能访问静态变量。
    >   一个类的静态方法不能够直接调用非静态方法。
    >   如访问控制权限允许,静态变量和静态方法也可以通过对象来访问,但是不被推荐。
    >   静态方法中不存在当前对象,因而不能使用 this,当然也不能使用 super。
    >   静态方法不能被非静态方法覆盖。
    >   构造方法不允许声明为 static 的。
    >   局部变量不能使用 static 修饰。
  • static 方法不需它所属的类的任何实例就会被调用,因此没有 this 值,不能访问实例变量,否则会引起编译错误。
  • 实例变量(类里面的成员变量)只能通过对象来访问,不能通过类访问。
  • 块是由大括号包围的一段代码。静态初始器(Static Initializer)是一个存在于类中、方法外面的静态块。静态初始器仅仅在类装载的时候(第一次使用类的时候)执行一次,用来初始化静态变量。
  • static块比构造函数先加载
  • 子类继承父类时,new子类的时候会先加载父类的 static 再加载子类的static,然后再加载父类的构造函数最后加载子类的构造函数。
  • 静态方法不可以通过对象调用,所以静态不能调用非静态变量,也不可以访问非静态成员变量。
30. Java final关键字:阻止继承和多态
  • 在 Java 中,声明类、变量和方法时,可使用关键字 final 来修饰。final 所修饰的数据具有终态的特征,表示“最终的”意思,具体规定如下:
    >  final 修饰的类不能被继承。
    >  final 修饰的方法不能被子类重写。
    >  final 修饰的变量(成员变量或局部变量)即成为常量,只能赋值一次不能修改值,常亮必须初始化。
    >  final 修饰的成员变量必须在声明的同时赋值,如果在声明的时候没有赋值,那么只有一次赋值的机会,而且只能在构造方法中显式赋值,然后才能使用。
    >  final 修饰的局部变量可以只声明不赋值,然后再进行一次性的赋值。
  • final 一般用于修饰那些通用性的功能、实现方式或取值不能随意被改变的数据,以避免被误用,例如实现数学三角方法、幂运算等功能的方法,以及数学常量π=3.141593、e=2.71828 等。
  • 为确保终态性,提供了上述方法和常量的 java.lang.Math 类也已被定义为 final 的。
  • 如果将引用类型(任何类的类型)的变量标记为 final,那么该变量不能指向任何其它对象。但可以改变对象的内容,因为只有引用本身是 final 的。
  • 如果变量被标记为 final,其结果是使它成为常数。想改变 final 变量的值会导致一个编译错误。
  • final 也可以用来修饰类(放在 class 关键字前面),阻止该类再派生出子类,例如 Java.lang.String 就是一个 final 类。
  • 上面这样做是出于安全原因,因为要保证一旦有字符串的引用,就必须是类 String 的字符串,而不是某个其它类的字符串(String 类可能被恶意继承并篡改)。
  • 方法也可以被 final 修饰,被 final 修饰的方法不能被覆盖(重写);变量也可以被 final 修饰,被 final 修饰的变量在创建对象以后就不允许改变它们的值了。
  • 一旦将一个类声明为 final,那么该类包含的方法也将被隐式地声明为 final,但是变量不是。
  • 被 final 修饰的方法为静态绑定,不会产生多态(动态绑定),程序在运行时不需要再检索方法表,能够提高代码的执行效率。
  • 在Java中,被 static 或 private 修饰的方法会被隐式的声明为 final,因为动态绑定没有意义。
  • 由于动态绑定会消耗资源并且很多时候没有必要,所以有一些程序员认为:除非有足够的理由使用多态性,否则应该将所有的方法都用 final 修饰。
  • 上面的认识未免有些偏激:
    >  因为 JVM 中的即时编译器能够实时监控程序的运行信息,可以准确的知道类之间的继承关系。如果一个方法没有被覆盖并且很短,编译器就能够对它进行优化处理,这个过程为称为内联(inlining)。
    >  例如,内联调用 e.getName() 将被替换为访问 e.name 变量。这是一项很有意义的改进,这是由于CPU在处理调用方法的指令时,使用的分支转移会扰乱预取指令的策略,所以,这被视为不受欢迎的。
    >  然而,如果 getName() 在另外一个类中被覆盖,那么编译器就无法知道覆盖的代码将会做什么操作,因此也就不能对它进行内联处理了。
    >  简单来说如果使用覆盖(重写),也就是多态,内联就不能使用了,编译器就不能做优化处理。
31. Object类
  • Object 类位于 java.lang 包中,是所有 Java 类的祖先,Java 中的每个类都由它扩展而来。
  • 在Java中,只有基本类型不是对象,例如数值、字符和布尔型的值都不是对象,所有的数组类型,不管是对象数组还是基本类型数组都是继承自 Object 类。
  • Object 类定义了一些有用的方法,由于是根类,这些方法在其他类中都存在,一般是进行了重载或覆盖,实现了各自的具体功能。
  • 在Java中,数据等价的基本含义是指两个数据的值相等。在通过 equals() 和“==”进行比较的时候,引用类型数据比较的是引用,即内存地址,基本数据类型比较的是值。
32. Object类 equals() 方法
  • Object 类中的 obj1.equals(obj2) 方法用来检测一个对象是否等价于另外一个对象:
    >  equals()方法只能比较引用类型,“”可以比较引用类型及基本类型。
    >  当用 equals() 方法进行比较时,对类 File、String、Date 及包装类来说,是比较类型及内容而不考虑引用的是否是同一个实例。
    >  用“
    ”进行比较时,符号两边的数据类型必须一致(可自动转换的数据类型除外),否则编译出错,而用 equals 方法比较的两个数据只要都是引用类型即可。
33. Object类 hashCode() 方法
  • Object 类中的散列码(hashCode)是按照一定的算法由对象得到的一个数值,散列码没有规律。如果 x 和 y 是不同的对象,x.hashCode() 与 y.hashCode() 基本上不会相同。
  • hashCode() 方法主要用来在集合中实现快速查找等操作,也可以用于对象的比较。
  • 在 Java 中,对 hashCode 的规定如下:
    >  在同一个应用程序执行期间,对同一个对象调用 hashCode(),必须返回相同的整数结果。前提是 equals() 所比较的信息都不曾被改动过。至于同一个应用程序在不同执行期所得的调用结果,无需一致。
    >  如果两个对象被 equals() 方法视为相等,那么对这两个对象调用 hashCode() 必须获得相同的整数结果。
    >  如果两个对象被 equals() 方法视为不相等,那么对这两个对象调用 hashCode() 不必产生不同的整数结果。然而程序员应该意识到,对不同对象产生不同的整数结果,有可能提升 hashTable 的效率。
  • 简单地说:如果两个对象相同,那么它们的 hashCode 值一定要相同。
  • 如果两个对象的 hashCode 值相同,它们并不一定相同。
  • 在 Java 规范里面规定,一般是覆盖(重写) equals() 方法应该连带覆盖 hashCode() 方法。
34. Object类 toString() 方法
  • toString() 方法是 Object 类中定义的另一个重要方法,是对象的字符串表现形式,返回值是 String 类型,用于描述当前对象的有关信息。
  • Object 类中实现的 toString() 方法是返回当前对象的类型和内存地址信息,但在一些子类(如 String、Date 等)中进行了重写,也可以根据需要在用户自定义类型中重写 toString() 方法,以返回更适用的信息。
  • 除显式调用对象的 toString() 方法外,在进行 String 与其它类型数据的连接操作时,会自动调用 toString() 方法。
35. 内部类
  • 在 Java 中,允许在一个类(或方法、语句块)的内部定义另一个类,称为内部类(Inner Class),也称为嵌套类(Nested Class)。
  • 内部类和外层封装它的类之间存在逻辑上的所属关系,一般只用在定义它的类或语句块之内,实现一些没有通用意义的功能逻辑,在外部引用它时必须给出完整的名称。
  • 使用内部类的主要原因有:
    >  内部类可以访问外部类中的数据,包括私有的数据。
    >  内部类可以对同一个包中的其他类隐藏起来。
    >  当想要定义一个回调函数且不想编写大量代码时,使用匿名(anonymous)内部类比较便捷。
    >  减少类的命名冲突。
36. Java抽象类的概念和使用
  • 自上而下的继承层次结构中,位于上层的类更具有通用性,甚至可能更加抽象。
  • 一般来说祖先类更加通用,它只包含一些最基本的成员,将它作为派生其他类的基类,而不会用来创建对象。
  • 甚至只给出方法的定义而不实现,由子类根据具体需求来具体实现。
  • 只给出方法定义而不具体实现的方法被称为抽象方法,抽象方法是没有方法体的,在代码的表达上就是没有{ }。
  • 包含一个或多个抽象方法的类也必须被声明为抽象类。
  • 使用 abstract 修饰符来表示抽象方法和抽象类。
  • 抽象类除了包含抽象方法外,还可以包含具体的变量和具体的方法。类即使不包含抽象方法,也可以被声明为抽象类,防止被实例化。
  • 抽象类不能直接使用,必须用子类去实现(重写)抽象类,然后使用其子类的实例。
  • 抽象类可以创建一个变量,其类型是一个抽象类,让它指向具体子类的一个实例,可以使用抽象类来充当形参,实现类作为实参,也就是多态的应用。
  • 抽象类可以继承抽象类。
  • 抽象类不能有抽象构造方法或抽象静态方法。
  • 一个类成为抽象类:
    >  当一个类的一个或多个方法是抽象方法时。
    >  当类是一个抽象类的子类,并且不能为任何抽象方法提供任何实现细节或方法主体时。
    >  当一个类实现一个接口,并且不能为任何抽象方法提供实现细节或方法主体时。
  • 抽象类一定包含抽象方法是错误的。 包含抽象方法的类一定是抽象类是正确的。
37. Java接口(interface)
  • 在抽象类中,可以包含一个或多个抽象方法;但在接口(interface)中,所有的方法必须都是抽象的,不能有方法体,它比抽象类更加“抽象”。
  • 接口使用 interface 关键字来声明,是一种特殊的抽象类,指定一个类必须做什么,而不是规定它如何去做。
    *接口中声明的成员变量默认都是 public static final 的,必须显示的初始化。因而在常量声明时可以省略这些修饰符。
  • 接口是若干常量和抽象方法的集合,和类的继承一样,接口也可以继承,子接口可以继承父接口中的常量和抽象方法并添加新的抽象方法。
  • 接口的特性:
    >  接口中只能定义抽象方法,这些方法默认为 public abstract 的,因而在声明方法时可以省略这些修饰符。
    >  试图在接口中定义实例变量、非抽象的实例方法及静态方法,都是非法的。
    >  接口中没有构造方法,不能被实例化。
    >   一个接口不实现另一个接口,但可以继承多个其他接口。接口的多继承特点弥补了类的单继承。
  • 使用接口的原因:使Java单继承的特性可以进行多继承。
  • 接口使得软件系统的灵活性和可扩展性,可插入性方面得到保证。
  • 接口不能直接使用 new 关键字来构建实例。
  • 接口必须通过类来实现(关键字:implements)它的抽象方法,然后再实例化类。
  • 如果一个类不能实现该接口的所有抽象方法,这个类必须被定义为抽象类。
  • 不允许创建接口的实例,但允许定义接口类型的引用变量,该变量指向了实现接口的类的实例。
  • 一个类只能继承一个父类,但却可以实现多个接口。
  • 接口作为引用类型来使用,任何实现该接口的类的实例都可以存储在该接口类型的变量中,通过这些变量可以访问类中所实现的接口中的方法,Java 运行时系统会动态地确定应该使用哪个类中的方法,实际上是调用相应的实现类的方法。
38. Java接口和抽象类的区别
  • 类是对象的模板,抽象类和接口可以看做是具体的类的模板。
  • 接口是一种特殊的抽象类,它们具有的相同点:
    >  都代表类树形结构的抽象层。在使用引用变量时,尽量使用类结构的抽象层,使方法的定义和实现分离,这样做对于代码有松散耦合的好处。
    >  都不能被实例化。
    >  都能包含抽象方法。抽象方法用来描述系统提供哪些功能,而不必关心具体的实现。
  • 抽象类和接口的主要区别:
    >  抽象类可以为部分方法提供实现,避免了在子类中重复实现这些方法,提高了代码的可重用性,这是抽象类的优势;而接口中只能包含抽象方法,不能包含任何实现。
    >  一个类只能继承一个直接的父类(可能是抽象类),但一个类可以实现多个接口,这个就是接口的优势。
  • 接口和抽象类各有优缺点,在接口和抽象类的选择上,必须遵守这样一个原则:
    >  行为模型应该总是通过接口而不是抽象类定义,所以通常是优先选用接口,尽量少用抽象类。
    >  选择抽象类的时候通常是如下情况:需要定义子类的行为,又要为子类提供通用的功能。
39. Java异常
  • 所有异常类型都是内置类Throwable的子类。
  • Throwable分成两个不同分支的子类,一个分支是Exception,另一类分支由Error。
  • 在Exception分支中有一个子类RuntimeException,该类型的异常自动定义(包括被零除和非法数组索引的错误)。
  • Error类型的异常用于Java运行时系统来显示与运行时系统本身有关的错误。
  • 处理异常有两个好处:第一,它允许你修正错误。第二,它防止程序自动终止。
  • finally块无论有没有异常抛出都会执行。
40. Java内置异常
  • 未经检查的异常(unchecked exceptions ):多数从RuntimeException派生的异常都自动可用,不需要被包含在任何方法的throws列表中,编译器不用检查它来看一个方法是否处理或抛出了这些异常。
为检查异常子类 说明
ArithmeticException 算术错误,如被0除
ArrayIndexOutOfBoundsException 数组下标出界
ArrayStoreException 数组元素赋值类型不兼容
ClassCastException 非法强制转换类型
IllegalArgumentException 调用方法的参数非法
IllegalMonitorStateException 非法监控操作,如等待一个未锁定线程
IllegalStateException 环境或应用状态不正确
IllegalThreadStateException 请求操作与当前线程状态不兼容
IndexOutOfBoundsException 某些类型索引越界
NullPointerException 非法使用空引用
NumberFormatException 字符串到数字格式非法转换
SecurityException 试图违反安全性
StringIndexOutOfBounds 试图在字符串边界之外索引
UnsupportedOperationException 遇到不支持的操作
  • 受检查的异常(checked exceptions):必须在方法的throws列表中包括的异常,如果这些方法能产生其中的某个异常但是不能自己处理它。
受检查异常 说明
ClassNotFoundException 找不到类
CloneNotSupportedException 试图克隆一个不能实现Cloneable接口的对象
IllegalAccessException 对一个类的访问被拒绝
InstantiationException 试图创建一个抽象类或者抽象接口的对象
InterruptedException 一个线程被另一个线程中断
NoSuchFieldException 请求的字段不存在
NoSuchMethodException 请求的方法不存在
41. 断言
  • 断言用于证明和测试程序的假设,比如“这里的值大于 5”。
  • 断言可以在运行时从代码中完全删除,所以对代码的运行速度没有影响。
42. Java线程
  • 程序中每个这样的部分都叫一个线程(thread),每个线程都有独立的执行路径。
  • 多线程程序包含两条或两条以上并发运行的部分,多线程是多任务处理的一种特殊形式。
  • 在基于线程(thread-based) 的多任务处理环境中,线程是最小的执行单位。
  • 多线程程序比多进程程序需要更少的内存消耗。
  • 进程需要分配独立的地址空间。
  • 线程共享相同的地址空间并且共同分享同一个进程。
  • 使用多进程任务处理环境时,多进程不受Java的控制,而多线程则受Java控制。
  • 多线程可以写出CPU最大利用率的高效程序,因为空闲时间保持最低,空闲时间是公共的。
  • 单线程环境,当一个线程因为等待资源时阻塞(block,挂起执行),整个程序停止运行。
  • 在任何时候,线程可以终止(terminate),这立即中断了它的运行。一旦终止,线程不能被恢复。
  • 作为绝对值,优先级是毫无意义的;当只有一个线程时,优先级高的线程并不比优先权低的线程运行的快。相反,线程的优先级是用来决定何时从一个运行的线程切换到另一个。
  • 线程可以自动放弃控制。在I/O未决定的情况下,睡眠或阻塞由明确的让步来完成。在这种假定下,所有其他的线程被检测,准备运行的最高优先级线程被授予CPU。
  • 线程可以被高优先级的线程抢占。在这种情况下,低优先级线程不主动放弃,处理器只是被先占——无论它正在干什么——处理器被高优先级的线程占据。基本上,一旦高优先级线程要运行,它就执行。这叫做有优先权的多任务处理。
  • 同步性管程(monitor):一个仅控制一个线程的小盒子。一旦线程进入管程,所有线程必须等待直到该线程退出了管程。用这种方法,管程可以用来防止共享的资源被多个线程操纵。
  • 主线程的重要性体现在两方面:
    >  它是产生其他子线程的线程;
    >  通常它必须最后完成执行,因为它执行各种关闭动作。
  • 两种方式实例化 Thread 对象创建线程:
    >   实现 Runnable 接口。
    >   继承 Thread 类。
  • 当两个或两个以上的线程需要共享资源,需要某种方法来确定资源在某一刻仅被一个线程占用,此过程叫做同步(synchronization)。
  • 同步的关键是管程(也叫信号量semaphore)。
  • 管程是一个互斥独占锁定的对象,或称互斥体(mutex)。
  • 在给定的时间,仅有一个线程可以获得管程。
  • 当一个线程需要锁定,它必须进入管程。所有其他的试图进入已经锁定的管程的线程必须挂起直到第一个线程退出管程。这些其他的线程被称为等待管程。一个拥有管程的线程如果愿意的话可以再次进入相同的管程。
  • 任何时候在多线程情况下,有一个方法或多个方法操纵对象的内部状态,都必须用synchronized 关键字来防止状态出现竞争。
  • 一旦线程进入实例的同步方法,没有其他线程可以进入相同实例的同步方法。然而,该实例的其他不同步方法却仍然可以被调用。
  • 为避免轮询,Java包含了通过wait( ),notify( )和notifyAll( )方法实现的一个进程间通信机制。这些方法在对象中是用final方法实现的,所以所有的类都含有它们。
  • 这三个方法仅在synchronized方法中才能被调用。
    >   wait( ) 告知被调用的线程放弃管程进入睡眠直到其他线程进入相同管程并且调用notify( )。
    >   notify( ) 恢复相同对象中第一个调用 wait( ) 的线程。
    >   notifyAll( ) 恢复相同对象中所有调用 wait( ) 的线程。具有最高优先级的线程最先运行。
43. 基本类型与引用类型
  • 基本类型:boolean、byte、short、int、long、float、double、char
  • 引用类型:Boolean、Byte、Short、Integer、Long、Float、Double、Character
44. 浅拷贝与深拷贝
  • 浅拷贝:只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存, 所以如果其中一个对象改变了这个地址,就会影响到另一个对象。
  • 深拷贝:是将一个对象从内存中完整的拷贝一份出来,从堆内存中开辟一个新的区域存放新对象,且修改新对象不会影响原对象。
45. mysql连接乱码解决
  • jdbc:mysql://localhost:3306/db4?characterEncoding=UTF-8
  • characterEncoding=UTF-8 指定字符的编码、解码格式。
46. 数据库连接池
  • 实际开发中“获得连接”或“释放资源”是非常消耗系统资源的两个过程,为了解决此类性能问题,采用连接池技术,来共享连接Connection。这样我们就不需要每次都创建连接、释放连接了,这些操作都交
    给了连接池。
  • 优点:用池来管理Connection,这样可以重复使用Connection。 当使用完Connection后,调用Connection的close()方法也不会真的关闭Connection,而是把Connection“归还”给池。
47. equal 和 ==
  • equal:是用来比较两个对象内部的内容是否相等的。原本是引用比较,但JDK大部分类都重写了 equals 方法,重写了 equals 方法,一定要重写 hashcode 方法。
  • equals相等,hashcode一定相等,反之hashcode相等,equals不一定为true
  • ==:是用来判断两个对象的地址是否相同,即是否是指相同一个对象。对于基本数据类型是值比较,对于引用类型是比较引用,看是否为同一个地址。
48. ArrayList 内存结构
  • ArrayList 存放数据的是数组
  • ArrayList 存放数据**(引用)**的始终是一块连续的内存空间
  • 初始化ArrayList时,在内存中分配一块区域,存放数组
  • 添加元素,如果分配的空间已经用完,就开辟一块大的空间,将原数据**(引用)**复制过去。
  • 删除元素的时候,将删除元素右侧的所有元素**(引用)**左移一位
  • arraylist存放的元素引用是连续的,引用指向的对象不是连续的,可能分散在不同的堆内存空间中。




作为程序员第 166 篇文章,每次写一句歌词记录一下,看看人生有几首歌的时间,wahahaha …

Lyric: 它在灌木丛旁邂逅

你可能感兴趣的:(java开发常遇问题,java,intellij-idea,开发语言)