Java知识点总结《基础篇》
小聊:本文主要编辑小白学习
Java
时感觉重要的、容易忘掉的的细节小知识或者知识补充。想着会对学习和使用Java
的查漏补缺很有帮助,就一点点记录下来了,内容比较多的知识点会另外写文章放在本专栏,所以这里的都是小tips
哦。整个Java语言部分,我会分为《基础篇》、《努力篇》和《补充篇》进行编写,补充篇也可能会不定期更新~本文为《基础篇》。
目前所有部分:
Java知识点总结《基础篇》
Java知识点总结《努力篇上》
Java知识点总结《努力篇下》
- Java JRE和JDK
- Java数据类型转换
- Java常量优化机制
- 在使用 +=、-= 时, 会自动将操作的结果类型强制转换为持有结果的类型
- 成员变量和局部变量的区别
- 栈、堆、方法区(概述)
- 标准代码——JavaBean
- 封装概念全面简述理解
- 继承概念全面简述理解
- super和this关键字
- 父类空间优于子类对象初始化
- 抽象类全面简述理解
- 接口全面简述理解
- 多态全面简述理解
- final(面试考点)
- 权限修饰符
- Java基本类型和包装类型
- 重写
- 重载
- 标识符和关键字
- == 和 equals 的区别
- 随笔
1. Java JRE和JDK
- JRE (Java Runtime Environment) :是
Java
程序的运行时环境,包含JVM
和运行时所需要的核心类库 。 - JDK (Java Development Kit):是
Java
程序开发工具包,包含JRE
和开发人员使用的工具。
我们想要运行一个已有的Java程序,那么只需安装 JRE
,想要开发一个全新的 Java
程序,那么必须安装 JDK
。
小贴士:
三者关系: JDK > JRE > JVM
2. Java数据类型转换
自动转换:不同类型运算时,结果会取值范围大的类型,所以返回值必须用大的接收,否则编译报错。
转换顺序规则
范围小的类型向范围大的类型提升,
byte
、short
、char
运算时直接提升为 int ,java
自动执行的。byte、short、char‐‐>int‐‐>long‐‐>float‐‐>double
强制转换:
将取值范围大的类型强制转换成取值范围小的类型 ,需要我们自己手动执行。
使用注意:
- 浮点转成整数,直接取消小数点,可能造成数据损失精度。
int
强制转成short
砍掉2个字节,可能造成数据丢失。
3. Java常量优化机制
- 在常量进行运算的时候,它的值是固定不变的。所以
java
虚拟机会自动进行运算(就是上面的自动隐式转换)。 然后判断是否超出了取值范围,如果没有超出就正常赋值。
public static void main(String[] args) {
//short类型变量,内存中2个字节
short s = 1;
/出现编译失败 s和1做运算的时候,1是int类型,s会被提升为int类型 s+1后的结果是int类型,将结果在赋值会short类型时发生错误 short内存2个字节,int类型4个字节 必须将int强制转成short才能完成赋值 /
s = s + 1; // 编译失败
s = (short)(s+1); // 需要手动强制,编译成功
System.out.println(s1); // 2
}
4. 在使用 +=
、-=
时, 会自动将操作的结果类型强制转换为持有结果的类型
什么意思?从Java常量优化机制中我们知道类型隐式转换的发生应用,还是这个例子
public static void main(String[] args) {
// 例子一
short s1 = 1;
// s1 = s1 + 1; // short类型在进行运算时会自动提升为int类型。Java编译检测报错,无关结果是否溢出
s1 += 1; // 正确写法,它的机制就是先将结果算出,再将结果强制转换为持有结果的类型,溢出就为负
System.out.println(s1); // 2
// 例子二(溢出情况)
short a = 32767;
short b = 1;
b += a;
System.out.println(b); // -32768
}
5. 成员变量和局部变量的区别
区别 | 成员变量 | 局部变量 |
---|---|---|
在类中的位置不同 (重点) | 类中,方法外 | 方法中或者方法声明上(形式参数) |
作用范围不一样 (重点) | 类中 | 方法中 |
初始化值的不同 (重点) | 有默认值 | 没有默认值。必须先定义,赋值,最后使用 |
在内存中的位置不同 (重点) | 堆内存 | 栈内存 |
生命周期不同 (了解) | 随着对象的创建而存在,随着对象的消失而消失 | 随着方法的调用而存在,随着方法的调用完毕而消失 |
6. 栈、堆、方法区(概述)
Java虚拟机的内存可以分为三个区域:栈
stack
、堆heap
、方法区method area
,方法区其实在堆的内部。JVM
的内存总构成为栈和堆。
栈stack
- 栈描述的是方法执行的内存模型。毎个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
JVM
为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)- 栈属于线程私有,不能实现线程间的共享
- 栈的存储特性是“先进后出,后进先出”(弹夹效果)
- 栈是由系统自动分配,速度快。栈是一个连续的内存空间
堆heap
- 堆用于存储创建好的对象和数组(数组也是对象)
JVM
只有一个堆,被所有线程共享- 堆是一个不连续的内存空间,分配灵活,速度慢!
方法区method area(又叫静态区)
JVM
只有一个方法区,被所有线程共享!- 方法区实际也是堆,只是用于存储类、常量相关的信息!
- 用来存放程序中永远是不变或唯一的内容。(类信息【
Class
对象】、静态变量、字符串常量等)
7. 标准代码——JavaBean
JavaBean
是Java
语言编写类的一种标准规范。符合JavaBean
的类,要求类必须是具体的和公共的,并且具有无参数的构造方法,提供用来操作成员变量的set
和get
方法。属性名称符合这种模式,其他
Java
类可以通过自省机制(反射机制)发现和操作这些JavaBean
的属性。
格式示例
package Demo;
/**
@Author 白忆宇
*/
public class Fruits {private String name;
private String color;/**
不写构造方法默认存在无参数的构造方法
*/
public Fruits() {}
public String getName() {
return name;
}public void setName(String name) {
this.name = name;
}public String getColor() {
return color;
}public void setColor(String color) {
this.color = color;
}
}
8. 封装概念全面简述理解
- 作用:代码之间的保护屏障,防止该类的代码和数据被其他类随意访问。要访问该类的数据,必须通过指定的方式。适当的封装可以让代码更容易理解与维护,也加强了代码的安全性。
靠什么实现封装特性
(1)private关键字(主要)
被private修饰后的成员变量和成员方法,只在本类中才能访问。对需要访问的成员变量,提供对应的一对 getXxx 方法 、 setXxx 方法。
(2)this关键字(封装优化1)
this
代表所在类的当前对象的引用(地址值),即对象自己的引用。
使用注意:方法被哪个对象调用,方法中的this
就代表那个对象。即谁在调用,this
就代表谁。(3)构造方法(封装优化2)
当一个对象被创建时候,构造方法用来初始化该对象,给对象的成员变量赋初始值。
使用注意:无论是否自定义构造方法,所有的类都有构造方法,因为Java
自动提供了一个无参数构造方法, 一旦自己定义了构造方法,Java
自动提供的默认无参数构造方法就会失效。
9. 继承概念全面简述理解
- 作用(好处):提高代码复用性,代码结构更简单;类与类之间产生了关系,是多态的前提。
- 原理:子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接访问父类中的非私有的属性和行为。
- 特点:只支持单继承。但是可以多层继承(继承体系)
- 弊端:类和类之间的耦合性太强,代码界“松耦合”的概念很重要,不要牵一发而动全身。
10. super和this关键字
关键字 | 含义 |
---|---|
super | 代表父类的存储空间标识(可以理解为父亲的引用) |
this | 代表当前对象的引用(谁调用就代表谁) |
用法
访问成员
this.成员变量 ‐‐ 本类的
super.成员变量 ‐‐ 父类的
this.成员方法名() ‐‐ 本类的
super.成员方法名() ‐‐ 父类的
访问构造方法
this(…) ‐‐ 本类的构造方法
super(…) ‐‐ 父类的构造方法
11. 父类空间优于子类对象初始化
在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非
private
修饰,则子类可以随意使用父类成员。代码体现在子类的构造方法调用时,一定先调用父类的构造方法。
举例简单面试题
- 问题:一个子类继承了一个父类,有另一个类初始化创建这个子类去使用时:子类无参构造方法、子类
static{}
代码块和父类无参构造方法、父类static{}
代码块,他们的执行顺序是什么? - 回答:父类静态代码块 > 子类静态代码块 > 父类构造方法 > 子类构造方法
代码解释
package Demo;
/**
* @Author 白忆宇
*/
class Dad {
static {
System.out.println("父类 static 初始化");
}
public Dad() {
System.out.println("父类构造方法初始化");
}
}
class Son extends Dad {
static {
System.out.println("子类 static 初始化");
}
public Son() {
System.out.println("子类构造方法初始化");
}
}
public class Main {
public static void main(String[] args) {
Son son = new Son();
}
}
// 输出
父类 static 初始化
子类 static 初始化
父类构造方法初始化
子类构造方法初始化
- 问题:一个子类继承了一个父类,有另一个类初始化创建这个子类去使用时:子类无参构造方法、子类
12. 抽象类全面简述理解
- 作用(好处):顾名思义,给子类方法提供抽象框架,因为不同子类此方法的实现会不同,继承抽象,具体实现由子类去做。这样的好处说白了也就是为了迎合
java
面向对象的特点,多一种开发思路。(小白后来觉得go
的大道至简也是一种真理,把复杂变简单才更难) 定义:修饰符 abstract 返回值类型 方法名 (参数列表);
public abstract void run();
- 使用注意:继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。
其它注意事项
抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
理解:假设创建了抽象类的对象,调用抽象的方法,而抽象方法没有具体的方法体,没有意义。
抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
理解:子类的构造方法中,有默认的super(),需要访问父类构造方法。
抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
理解:未包含抽象方法的抽象类,目的就是不想让调用者创建该类对象,通常用于某些特殊的类结构设计。
抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
理解:假设不重写所有抽象方法,则类中可能包含抽象方法。那么创建对象后,调用抽象的方法,没有意义。
简单使用举例:(可不看)
package Demo;
/**
* @Author 白忆宇
*/
abstract class Animal {
private String animalName;
public String getAnimalName() {
return animalName;
}
public void setAnimalName(String animalName) {
this.animalName = animalName;
}
/**
* 抽象方法action()
*/
abstract void action();
}
class Dog extends Animal {
@Override
void action() {
System.out.println("我是" + super.getAnimalName() + ",我爱摇尾巴");
}
}
class Cat extends Animal {
@Override
void action() {
System.out.println("我是" + super.getAnimalName() + ",我爱喵喵叫");
}
}
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
dog.setAnimalName("狗");
dog.action();
Animal cat = new Cat();
cat.setAnimalName("猫");
cat.action();
}
}
// 输出
我是狗,我爱摇尾巴
我是猫,我爱喵喵叫
13. 接口全面简述理解
- 作用:最大的好处就是提高代码可维护性。比如:控制类通过接口去调用实现类方法,当修改实现类时,不需要再动控制类了,只需要修改接口实现,spring开发模式框架就是如此。具体原理可以结合Java面向对象的依赖倒转设计原则理解。
- 介绍:是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么接口的内部主要就是封装了方法,包含抽象方法(JDK 7及以前),默认方法和静态方法(JDK 8),私有方法(JDK 9)。
定义:public interface 接口名{}
public interface animal {
//抽象方法:使用 abstract 关键字修饰,可以省略,没有方法体。该方法供子类实现使用。
public abstract void eat();
//静态方法:使用 static 修饰,供接口直接调用。
public static void sleep();
//私有方法或私有静态方法:使用 private 修饰,供接口中的默认方法或者静态方法调用。
private (static) void run();
//默认方法:使用 default 修饰,不可省略,供子类调用或者子类重写。
public default void fight();
}
使用注意
- 非抽象子类实现接口必须实现 接口中所有抽象方法;一个类可以实现多个接口
- 实现接口
vs
继承类:一个类只能继承一个父类,而同时实现多个接口 - 当一个类,既继承一个父类,又实现若干个接口时,父类中的成员方法与接口中的默认方法重名,子类就近选择执行父类的成员方法。
其它 tips
- 接口中,无法定义成员变量,但是可以定义常量,其值不可以改变,默认使用 public static final 修饰。
- 接口中,没有构造方法,不能创建对象。
- 接口中,没有静态代码块。
14. 多态全面简述理解
- 作用:比如:无论之后再多的子类出现,我们都不需要编写 getXxx/setXxx 方法了,直接使用父类 getXxx/setXxx 都可以完成。可以使程序编写的更简单,并有良好的扩展。
- 定义:多态是继封装、继承之后,面向对象的第三大特性。它是指同一行为,具有多个不同表现形式。比如:生物们的活动方式:人行走、鱼游泳、鸟飞行……
使用:父类类型 变量名 = new 子类对象; 变量名.方法名();
Fu f = new Zi();
f.method();
其它注意
- 继承或者实现【二选一】
- 方法的重写【意义体现:不重写,无意义】
- 父类引用指向子类对象【格式体现】
- 父类引用,想要调用子类特有的方法,必须做向下转型。(多态小限制)
使用举例(可不看)
package Demo;
/**
* @Author 白忆宇
*/
abstract class Fruits {
public abstract void color();
}
class Banana extends Fruits {
@Override
public void color() {
System.out.println("黄色~");
}
}
class Grape extends Fruits {
@Override
public void color() {
System.out.println("紫色~");
}
}
public class Main {
public static void main(String[] args) {
Banana banana = new Banana();
Grape grape = new Grape();
getFruitsColor(banana);
getFruitsColor(grape);
}
public static void getFruitsColor(Fruits fruit) {
fruit.color();
}
}
// 输出
黄色~
紫色~
15. final(面试考点)
特点:不可改变。可以用于修饰类、方法和变量。
类:被修饰的类,不能被继承。
方法:被修饰的方法,不能被重写。 而且
JVM
会尝试将其内联,以提高运行效率。变量:被修饰的变量,不能被重新赋值。如果修饰引用,那么表示引用不可变,引用指向的内容可变。
常量:被修饰的常量名称,一般都有书写规范,所有字母都大写。在编译阶段会存入常量池中。
final有关重排序规则
- 在构造函数内对一个
final
域的写入,与随后把这个被构造对象的引用赋值给一个引用变量,这两个操作之间不能重排序。 - 初次读一个包含
final
域的对象的引用,,与随后初次读这个final
域,这两个操作之间不能重排序。
- 在构造函数内对一个
16. 权限修饰符
public:公共的。
protected:受保护的
default:默认的
private:私有的
public | protected | default | private | |
---|---|---|---|---|
同一类中 | √ | √ | √ | √ |
同一包中(子类与无关类) | √ | √ | √ | |
不同包的子类 | √ | √ | ||
不同包中的无关类 | √ |
实用建议
- 成员变量使用
private
,隐藏细节。 - 构造方法使用
public
,方便创建对象。 - 成员方法看权限需求,一般使用
public
- 成员变量使用
17. Java基本类型和包装类型
八种基本数据类型即其封装类
基本类型 | 默认值 | 封装类型 |
---|---|---|
short | 0 | Short |
int | 0 | Integer |
float | 0.0 | Float |
double | 0.0 | Double |
long | 0 | Long |
byte | 0 | Byte |
boolean | false | Boolean |
char | \u0000 | Character |
- 成员变量封装类型的默认值都是
null
- 基本数据类型在声明时系统会自动给它分配空间,而引用类型声明时只是分配了引用空间,必须通过实例化开辟数据空间之后才可以赋值。
18. 重写
重写定义(Override)
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写 (
Override
)。子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
重写的方法前面规范加注解
@Override
(可以不加)。使用举例(可不看)
package Demo;
class Dad {
public void action(String action) {
System.out.println("爸爸爱"+action);
}
}
class Son extends Dad {
public Son() {
}
public void action() {
System.out.println("我是儿子在睡觉");
}
@Override
//重写的好处可以在原来的基础上修改和添加操作
public void action(String action) {
super.action(action);
System.out.println("儿子爱"+action);
}
}
public class Main {
public static void main(String[] args) {
Son son1 = new Son();
son1.action();
son1.action("睡觉");
}
}
输出:
我是儿子在睡觉
爸爸爱睡觉
儿子爱睡觉
总结
- 方法名,参数列表,返回类型(除过子类中方法的返回类型是父类中返回类型的子类)必须相同
- 子类方法覆盖父类方法,必须要保证权限大于等于父类权限。 (比如子类时
default
,父类就不能是public
) - 重写时,在方法中可以调用 super.父类成员方法,表示调用父类的成员方法。
19. 重载
重载定义(Overload)
在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。
使用举例(可不看)
package Demo;
/**
- @Author 白忆宇
*/
class Person {
public void sayHello() {
System.out.println("I say Hello");
}
public void sayHello(String who) {
System.out.println(who + " say Hello");
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person();
person.sayHello();
person.sayHello("Tom");
}
}
// 输出
I say Hello
Tom say Hello- @Author 白忆宇
总结
- 重载
Overload
是一个类中多态性的一种表现 - 重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)
- 重载的时候,返回值类型可以相同也可以不相同。不能以返回型别作为和重载的区分标准
- 重写发生在父类与子类中,重载是在同一个类中定义的不同表现形式
- 重载
20. 标识符和关键字
标识符是程序员为程序、类、变量、方法取的名字。
关键字是Java语言内部使用所标识的名字,属于特殊的标识符。
Java
常见关键字
类型 | 关键字 |
---|---|
访问控制 | private、protected、public |
类、方法和变量 | abstract、new、class、static、extends、final、implements、interface、native、strictfp、synchronized、transient、volatile |
程序控制 | break、for、continue、instanceof、return、do、while、if、else、switch、case、default |
错误处理 | try、catch、throw、throws、finally |
包相关 | import、package |
基本类型 | boolean、char、byte、double、float、int、long、short、null、true、fasle |
变量引用 | super、this、void |
保留字 | goto、const |
21. == 和 equals 的区别
- ==
基本数据类型 ==
比较的是值,引用数据类型 ==
比较的是内存地址。
- equals()
它的作用也是判断两个对象是否相等,它不能用于比较基本数据类型的变量。equals()
方法存在于 Object
类中,而 Object
类是所有类的直接或间接父类。而且其默认实现方式就是 ==
,当然定义类时可重写 equals()
方法
// 默认实现
public boolean equals(Object obj) {
return (this == obj);
}
- String中的equals方法
因为 Sring
不是基本类型,本来比较的是地址值,但是它比较特别,String
类中的 equals
方法是原本就被重写过的,改成了比较对象的值。当创建 String
类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String
对象。
还没有评论,来说两句吧...