注:本文参考自菜鸟教程,部分图片也来自菜鸟教程
菜鸟教程:https://www.runoob.com/java/java-tutorial.html
- JDK(Java Development Kit):Java开发工具包,jdk是整个Java开发的核心,它集成了jre和一些好用的小工具(javac.exe,java.exe,jar.exe等)。
- JRE(Java Runtime Environment):Java运行时环境。主要包含两个部分,jvm的标准实现和java的一些基本类库。它相对于jvm来说,多出来的是一部分的java类库。
- JVM(Java Virtual Machine):Java虚拟机。只认识xxx.class类型文件,它能够将class文件中的字节码指令进行识别并调用操作系统向上的API完成动作。所以说jvm是Java能够跨平台的核心。
三者关系可以理解为嵌套关系:JDK>JRE>JVM
什么是==
== 比较运算符,如果进行比较的两个操作数都是数值类型,即使他们的数据类型不相同,只要他们的值相等,也都将返回true.如果两个操作数都是引用类型,那么只有当两个引用变量的类型具有父子关系时才可以比较,而且这两个引用必须指向同一个对象,才会返回true.(在这里我们可以理解成==比较的是两个变量的内存地址)
什么是equals()
equals()方法是Object类的方法,在Object类中的equals()方法体内实际上返回的就是使用==进行比较的结果.但是我们知道所有的类都继承Object,而且Object中的equals()方法没有使用final关键字修饰,那么当我们使用equal()方法进行比较的时候,我们需要关注的就是这个类有没有重写Object中的equals()方法.
区别
- ==是判断两个变量或实例是不是指向同一个内存空间,equals()是判断两个变量或实例所指向的内存空间的值是不是相同。
- ==是指对内存地址进行比较,equals()是对字符串的内容进行比较。
- ==是指引用是否相同,equals()是指的值是否相同。
int 和 Integer比较
public static void main(String[] args) {
System.out.println("-128 ~ +127 之间");
Integer a = 5;
int b = 5;
Integer c = new Integer(5);
Integer d = 5;
System.out.println(a.equals(b));
System.out.println(a == b);
System.out.println(a.equals(c));
System.out.println(a == c);
System.out.println(a == d);
System.out.println("--------------------------");
System.out.println("-128 ~ +127 之外");
a = 128;
b = 128;
c = new Integer(128);
d = 128;
System.out.println(a.equals(b));
System.out.println(a == b);
System.out.println(a.equals(c));
System.out.println(a == c);
System.out.println(a == d);
}
final是Java的关键字,可用于三个地方(修饰类,修饰方法和修饰变量)。
特征:凡是引用final关键字的地方皆不可修改
- 修饰类:表示该类不能被继承。
- 修饰方法:表示方法不能被重写。
- 修饰变量:表示变量只能一次赋值以后值不能被修改(可以理解为常量)
可参考:https://blog.csdn.net/qq_24309787/article/details/100942044
- &与&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算运算结果才为true,否则,只要有一方为false,则结果也为false。
- &&还具有短路功能,即如果第一个表达式为false,则不再计算第二个表达式。
- &还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作。
简单的说:
&是位运算,返回结果是int型。
&&是逻辑运算,返回结果是boolean型。
&不管前面的条件是否正确,后面都执行。
&&前面条件正确时,才执行后面,不正确时,就不执行,就效率而言,这个更好。
扩展:
java中&和&&的区别,java中||和|符号的区别
(&,|)它们是逻辑操作,(&&,||)它们是条件操作。
&是位运算符,表示按位与运算,&&是逻辑运算符,表示逻辑运算与(and).
|是按位或运算符 ,表示按位或运算,||是逻辑或算符,表示逻辑或运算。
条件操作只能操作布尔型的,而逻辑操作不仅可以操作布尔型,而且可以操作数值型的。
不同点:
对于A&B,不管a是否为假,仍然要判断B。
对于A|B,不管a是否为真,仍然要判断B。
而对于A&&B,A||B在以上情况就不会去判断B了。
不一定。
反过来equals为true时,hashCode一定相同。
类的hashCode方法和equals方法都可以重写,返回值完全在于自己定义。
hashCode() 返回该对象的哈希码值;equals() 返回两个对象是否相等。
关于 hashCode 和 equals 方法是有一些 常规协定 :
1、两个对象用 equals() 比较返回true,那么两个对象的 hashCode() 方法必须返回相同的结果。
2、两个对象用 equals() 比较返回false,不要求 hashCode() 方法也一定返回不同的值,但是最好返回不同值,以提搞哈希表性能。
3、重写 equals() 方法,必须重写 hashCode() 方法,以保证 equals 方法相等时两个对象 hashcode 返回相同的值。
String,StringBuffer,StringBuilder
- String:final修饰,String类的方法都是返回new String。即对String对象的任何改变都不影响原对象,对字符串的修改操作都会生成新的对象,不可被继承。
- StringBuffer:对字符串的操作方法都加了synchronized,保证线程安全。
- StringBuilder:不保存线程安全,在方法体内需要进行字符串的修改操作,可以new StringBuilder对象,调用StringBuilder对象的append,replace,delete等方法修改字符串。
- 当对象通过
传值
调用时,传递的是这个对象的一个拷贝
。因此,即使函数修改这个对象,也不会影响原对象的值。- 当对象通过
传引用
调用时,对象本身没有被传递,而传递的是对象的一个引用
。因此,外部函数对这个对象的修改,也会反映到任何出现这个对象的地方。
什么情况下发生传值,什么情况下发生传引用
- 如果是基本数据类型和String,则实参不会改变,因为传的是值。
- 但如果传的是对象集合或者数组,就会改变,因为传的是引用。
- 装箱:将基本类型用他们对应的引用类型包装起来
- 拆箱:将包装类型转换为基本数据类型
- 自动装箱表示对于byte、short、int、long、float、double、boolean、char,可以自动将其转换成对应的Byte、Short、Integer、Long、Float、Double、Boolean、Char对象。
- 自动拆箱则是自动装箱的反过程。
父类静态成员和静态代码块->子类静态成员和静态代码块->父类非静态成员和非静态代码块->父类构造方法->子类非静态成员和非静态代码块->子类构造方法
可参考:http://gityuan.com/2016/01/24/java-classloader/
启动类加载器,扩展类加载器,应用程序类加载器,用户自定义类加载器。
ClassLoader即常说的类加载器,其功能是用于从Class文件加载所需的类,主要场景用于热部署、代码热替换等场景。系统提供3种的类加载器:Bootstrap ClassLoader、Extension ClassLoader、Application ClassLoader
- Bootstrap ClassLoader
启动类加载器
,一般有C++实现,是虚拟机的一部分。该类加载器主要职责是将JAVA_HOME路径下的\lib目录中能被虚拟机是被的类库(比如rt.jar)加载到虚拟机内存中。Java程序无法直接引用该类加载器。- Extension ClassLoader
扩展类加载器
,由Java实现,独立于虚拟机的外部。该类加载器主要职责将JAVA_HOME路径下的\lib\ext目录中的所有类库,开发者可直接使用扩展类加载器。 该加载器是由sun.misc.Launcher$ExtClassLoader实现。- Application ClassLoader
应用程序类加载器
,该加载器是由sun.misc.Launcher$AppClassLoader实现,该类加载器负责加载用户类路径上所指定的类库。开发者可通过ClassLoader.getSystemClassLoader()方法直接获取,故又称为系统类加载器。当应用程序没有自定义类加载器时,默认采用该类加载器。- CustomClassLoader
自定义类加载器
,通过继承ClassLoader类实现,主要重写findClass方法。
扩展
类加载器的层级查找顺序依次为:启动类加载器,扩展类加载器,系统类加载器。系统类加载器是默认的应用程序类加载器。
当某个特定的类加载器它在接到需要加载类的请求时,这个类会首先查看自己已加载完的类中是否包含这个类,如果有就返回,没有的话就会把加载的任务交给父类加载器加载,以此递归,父类加载器如果可以完成类加载任务,就返回它,当父类加载器无法完成这个加载任务时,才会不得已自己去加载。这种机制就叫做双亲委派机制。
- switch可作用于char byte short int。
- switch可作用于char byte short int对应的包装类。
- switch不可作用于long double float boolean,包括他们的包装类 Long/Double。
- switch中可以是字符串类型,String(jdk1.7之后才可以作用在String上)。
- switch中可以是枚举类型。
在return前执行
- try中的return语句调用的函数先于finally中调用的函数执行,也就是说return语句先执行,finally语句后执行。
- return并不是让函数马上返回,而是return语句执行后,将把返回结果放置进函数栈中,此时函数并不是马上返回,它要执行finally语句后才真正开始返回。
可参考:https://www.runoob.com/java/java-number.html
Math 的 floor,round 和 ceil 方法实例比较
- final 是一个修饰符,可以修饰变量、方法和类。如果 final 修饰变量,意味着该变量的值在初始化后不能被改变。
- finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的,但是什么时候调用 finalize 没有保证。
- finally 是一个关键字,与 try 和 catch 一起用于异常的处理。finally 块一定会被执行,无论在 try 块中是否有发生异常。
- 方法的重载和重写都是实现多态的方式。
- 重载实现的是编译时的多态性,重写实现的是运行时的多态性。
- 重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。
每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。
最常用的地方就是构造器的重载。- 重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。
扩展
:多态是同一个行为具有多个不同表现形式或形态的能力。
方法重写规则
扩展
:当需要在子类中调用父类的被重写方法时,要使用 super 关键字。
class Animal{
public void move(){
System.out.println("动物可以移动");
}
}
class Dog extends Animal{
public void move(){
super.move(); // 应用super类的方法
System.out.println("狗可以跑和走");
}
}
public class TestDog{
public static void main(String args[]){
Animal b = new Dog(); // Dog 对象
b.move(); //执行 Dog类的方法
}
}
输出结果:
动物可以移动
狗可以跑和走
方法的重载规则
重写与重载之间的区别
区别点 | 重载 | 重写 |
---|---|---|
参数列表 | 必须修改 | 不能修改 |
返回类型 | 可以修改 | 不能修改 |
异常 | 可以修改 | 可以减少或删除,但不能抛出新的或者更广的异常 |
访问 | 可以修改 | 不能做更严格的限制(可以降低限制public>protected>default>private) |
总结
方法的重写(Overriding)和重载(Overloading)是java多态性的不同表现,重写是父类与子类之间多态性的一种表现,重载可以理解成多态的具体表现形式
。
继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力
类的继承格式
通过 extends
关键字实现继承关系
class 父类 {
}
class 子类 extends 父类 {
}
继承的特性
- 子类拥有父类非private的属性、方法。
- 子类可以拥有自己的属性和方法、即子类可以对父类进行扩展。
- java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
- 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
继承类型
Java 不支持多继承,但支持多重继承。
扩展:
super 与 this 关键字
super关键字:我们可以通过super关键字来实现对父类成员的访问,用来引用当前对象的父类。
this关键字:指向自己的引用。
class Animal {
void eat() {
System.out.println("11111");
}
}
class Dog extends Animal {
void eat() {
System.out.println("22222");
}
void eatTest() {
this.eat(); // this 调用自己的方法
super.eat(); // super 调用父类方法
}
}
public class Test {
public static void main(String[] args) {
Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.eatTest();
}
}
输出结果:
11111
22222
11111
final关键字
final 关键字声明类可以把类定义为不能继承的,即最终类;或者用于修饰方法,该方法不能被子类重写:
声明类:
final class 类名 {//类体}
声明方法:
修饰符(public/private/default/protected) final 返回值类型 方法名(){//方法体}
注:实例变量也可以被定义为 final,被定义为 final 的变量不能被修改。被声明为 final 类的方法自动地声明为 final,但是实例变量并不是 final。
构造器
子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式)。如果父类的构造器带有参数,则必须在子类的构造器中显式地通过 super 关键字调用父类的构造器并配以适当的参数列表。
如果父类构造器没有参数,则在子类的构造器中不需要使用 super 关键字调用父类构造器,系统会自动调用父类的无参构造器。
- 多态是同一个行为具有多个不同表现形式或形态的能力。
- 多态就是同一个接口,使用不同的实例而执行不同的操作。
- 多态性是对象多种表现形式的体现。
多态的优点
消除类型之间的耦合关系
可替换性:多态对已存在的代码具有可替换性。
可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际 上新加子类更容易获得多态功能。
接口性:多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
灵活性:它在应用中体现了灵活多样的操作,提高了使用效率。
简化性:多态简化了对应用软件的代码编写和修改过程。
实现多态的两种形式
public void play(Pet p){}
public Pet getPet(int type){}
多态存在的三个必要条件
- 编写具有继承关系的父类,子类。
- 子类重写父类方法。
- 使用父类的引用指向子类对象。
将类的某些信息隐藏在类的内部,不允许外部程序直接访问,并通过该类提供的方法来实现对隐藏信息的操作和访问。(简单的说就是隐藏对象的信息,留出访问的接口)。
封装的优点
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员变量进行更精确的控制。
- 隐藏信息,实现细节。
用abstract 关键字来修饰一个类时,这个类叫作抽象类。抽象类是它的所有子类的公共属性的集合,是包含一个或多个抽象方法的类。抽象类可以看作是对类的进一步抽象。在面向对象领域,抽象类主要用来进行类型隐藏。
抽象类格式
public abstract class ClassName {…}
抽象方法是一种特殊的方法:它只有声明,而没有具体的实现。抽象方法格式
public abstract class Employee
{
public abstract double computePay();
}
- 抽象方法必须用abstract关键字进行修饰。如果一个类含有抽象方法,则称这个类为抽象类,抽象类必须在类前用abstract关键字修饰。因为抽象类中含有无具体实现的方法,所以不能用抽象类创建对象。
- 包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类一样,同样可以拥有成员变量和普通的成员方法。
抽象类和普通类的区别
- 抽象方法必须为public或者protected(因为如果为private,则不能被子类继承,子类便无法实现该方法),缺省情况下默认为public。
- 抽象类不能用来创建对象。
- 如果一个类继承于一个抽象类,则子类必须实现父类的抽象方法。如果子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类
接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。
- 接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。
类描述对象的属性和方法。接口则包含类要实现的方法。
除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。
另外,在 Java 中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。
接口的声明语法格式
public interface 接口名称 [extends 其他的接口名] {
// 声明变量(任何类型 final, static 字段)
// 抽象方法
}
接口的实现
当类实现接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。
类使用implements关键字实现接口。在类声明中,Implements关键字放在class声明后面。
语法格式
public class 类名 implements 接口名称1,接口名称2...{
//方法
}
接口特性
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
- 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
接口与类的区别
- 接口不能用于实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法,Java 8 之后 接口中可以使用 default 关键字修饰的非抽象方法。
- 接口不能包含成员变量,除了 static 和 final 变量。
- 接口不是被类继承了,而是要被类实现。
- 接口支持多继承。
扩展
接口和抽象类的区别
- 子类只能继承一个抽象类,但可以实现任意多个接口。
- 接口中的方法都是抽象方法,抽象类可以有非抽象方法。
- 抽象类中的成员变量可以是各种类型,接口中的成员变量只能是静态常量。
- 抽象类中可以有静态方法和静态代码块,而接口中不行。
- 接口没有构造方法, 抽象类里可以有构造方法。
什么时候使用接口?什么时候使用抽象类?
使用抽象类是为了代码的复用,而使用接口的动机是为了实现多态性。
抽象类适合用来定义某个领域的固有属性,也就是本质,接口适合用来定义某个领域的扩展功能。
一、什么时候使用抽象类?
- 当2个或多个类中有重复部分的时候,我们可以抽象出来一个基类,如果希望这个基类不能被实例化,就可以把这个基类设计成抽象类。
当需要为一些类提供公共的实现代码时,应优先考虑抽象类 。
因为抽象类中的非抽象方法可以被子类继承下来,使实现功能的代码更简单。- 抽象类只能是单继承的,不能多继承。
二、什么时候使用接口?
当注重代码的扩展性跟可维护性时,应当优先采用接口。
①接口与实现它的类之间可以不存在任何层次关系,接口可以实现毫不相关类的相同行为,比抽象类的使用更加方便灵活;
②接口只关心对象之间的交互的方法,而不关心对象所对应的具体类。接口是程序之间的一个协议,比抽象类的使用更安全、清晰。一般使用接口的情况更多。
封装:
将类的某些信息隐藏在类内部,不允许外部程序直接访问,而是通过该类提供的方法来实现对隐藏信息的操作和访问。
继承:
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择地继承父类。通过使用继承我们能够非常方便地复用以前的代码。
- 子类拥有父类非private的属性和方法。
- 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
- 子类可以用自己的方式实现父类的方法。
多态:
是同一个行为具有多个不同表现形式或形态的能力。
实现多态:
1》编写具有继承关系的父类,子类 。
2》子类重写父类方法。
3》使用父类的引用指向子类对象。
实现多态的两种形式:
1》使用父类作为方法形参实现多态 。
2》使用父类作为方法返回值实现多态。