Java基础
1. 开发环境
1.1 Java的语言特性
-
简单性
-
面向对象
-
可移植性
-
健壮性
-
多线程
-
安全性
1.2 JDK、JRE、JVM
原文链接:https://blog.csdn.net/qq_35326718/article/details/79443911
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 虚拟机。它能够识别class字节码文件并调用操作系统向上的 API 完成动作。所以说,jvm 是 Java 能够跨平台的核心。
1.3 Java程序在运行时具体的操作流程
-
Java运行包括两个阶段:编译阶段 和 运行阶段
-
编译阶段:
JDK中有一个编译器:javac.exe,负责编译阶段
前提:xxx.java文件符合java语法规则
javac.exe可以将源文件( xxx.java) 转换成 字节码文件(xxx.class)
- 如何使用javac.exe?
//DOS窗口下 javac 源文件路径
-
运行阶段:
JDK中有一个工具:java.exe ,负责运行阶段
- java.exe会启动Java虚拟机(JVM)
- JVM会启动类加载器ClassLoader
- ClassLoader会根据classpath环境变量指定的路径(没有配置,就从当前目录下)搜索.class文件,将其加载到JVM中
- JVM将字节码文件,解释成二进制文件,并调用操作系统向上的 API
- 最后操作系统执行二进制文件和底层硬件平台进行交互
-
如何使用java.exe?
//DOS窗口下 java 类名
-
-
1.4 字节码和源码文件位置
SE类库的字节码:rt.jar
J:\JAVA\jdk1.8.0_144\jre\lib\rt.jar
SE类库的源码:src.zip
J:\JAVA\jdk1.8.0_144\src.zip
1.5 public class 和 class区别
public class:
一个java源文件中,只能有一个公开的class文件,并且类名必须和java源文件一致
class:
一个java源文件中,可以有0或多个class文件,一个class文件会生成一个xx.class字节码文件
2. Java语言基础
1.1 标识符
1.什么是标识符?
类名、方法名、变量名、常量名…
2.标识符命名规则
-
只能由数字、字母、下划线、美元符号组成,不能有其他符号
-
不能以数字开头
-
严格区分大小写
-
关键字不能做标识符
3.标识符命名规范
- 最好见名知意、驼峰命名方式
- 类名、接口名:首字母大写,后面每个单词首字母大写
- 变量名、方法名:首字母小写,后面每个单词首字母大写
- 常量名:全部大写
1.2 变量
- 什么是变量?
- 变量的本质是内存空间,它包含三个部分: 数据类型、变量名、字面值
- 变量是内存中存储数据的最基本的单元
-
变量的分类
-
按变量声明的位置分类
-
成员变量:声明在类体中的变量,如果没有赋值,系统会赋予默认值
-
局部变量:声明在方法体中的变量,必须赋予初始值,才能使用
-
-
按变量的数据类型分类
-
基本数据类型
- 存放在栈内存中的局部变量表
- 基本数据类型作用:指导程序在运行阶段,应该分配多大的内存空间
-
引用数据类型
- 分配两块内存,new出的对象存放在堆内存,引用变量存放在栈内存中的局部变量表中
-
-
按static修饰的变量分类
- **静态变量:**有static修饰的变量,属于类本身,存放在方法区中的静态存储区
- **实例变量:**无static修饰的变量,属于该类的实例,存放在堆内存中
-
1.3 数据类型
1. 基本数据类型
1. 八种基本数据类型
基本数据类型 | 占用字节 | 默认值 | 取值范围 | 包装类 |
---|---|---|---|---|
byte | 1 | 0 | -128~127 | Byte |
short | 2 | 0 | -32768~32767 | Short |
int | 4 | 0 | Integer | |
long | 8 | 0 | Long | |
float | 4 | 0.0 | Float | |
double | 8 | 0.0 | Double | |
boolean | 1 | false | false、true | Boolean |
char | 2 | \u0000 | 0~65535 | Character |
2. 基本数据类型转换
容量大小:
byte < short < int < long < float < double
char <
- 自动类型转换 (小容量–>大容量)
long x = 456;
/*
456:是int类型的字面值
x是long类型的变量,小容量int自动转换成大容量long
自动类型转换
*/
byte y = 128;//编译报错,128字面值,超出byte范围
- 强制类型转换 (大容量 --> 小容量)
例1:
long x = 100L;
//编译报错:大容量转换小容量,需要强制类型转换
//int y = x;
int y = (int)x;
例2:
//3.0是double类型字面值
//x是double类型,不存在类型转换
double x = 3.0;
//3.0是double类型字面值,占用8个字节
//f是float类型,占用4个字节
//大容量转换成小容量,要有强制类型转符
float f = (float)3.0;//float f = 3.0f;
面试题
例子1:
1.java中 2*0.1 == 0.2将会返回true还是false?
false,因为浮点数不能完全精确的表示出来,一般会损失精度。
例子2:
/*
2147483648被当作int类型4个字节处理,超出int类型范围
无法编译通过
*/
long y = 2147483648;
//修改,将2147483648当作长整型
long y = 2147483648L;//long y = (long)2147483648;
例子3:java中float f = 3.4;是否正确?
编译错误,3.4是double类型,f变量是float类型,大容量转换成小容量需要强制类型转。
修改:
float f = (float)3.4;//float f = 3.4f;
例子3:关于自加,自减
//++ 出现在变量后,先做赋值运算,在对变量中保存的值自加1
int a = 100;
int b = a ++;
System.out.println(a);//101
//先做b = a,再做a自加1运算
System.out.println(b);//100
//++ 出现在变量前,先做变量自加1,再赋值
int m = 20;
int n = ++ m;
System.out.println(m);//21
System.out.println(n);//21
//由于函数底层封装的public void println(int x)
int e = 100;
//即x = e ++;
System.out.println(e ++);//100:先赋值给x=100,再e自加1
System.out.println(e);//101
int s = 100;
//即x = ++ s;
System.out.println(++ s);//101:先s自加1,再赋值给x=101
System.out.println(s);//101
3. 封装类
-
什么是封装类:
- java提供了8种基本数据类型及对应的 8 种封装数据类型。
-
封装类的作用:
- java是面向对象编程的语言,封装类解决了基本数据类型无法面向对象的问题。
-
使用场景:
-
集合类的泛型只能使用封装类
List<int> ls = new ArrayList<>();//编译报错 List<Integer> ls = new ArrayList<>();
-
成员变量不能有默认值
private int a;//int 默认值为0,所以a=0 private Integer a;//Integer 默认是空。
-
封装类可以表示0和空,两种状态。比如没有参加考试的人,和考试等于0分的人
-
封装类可以将字符串解析成基本数据类型
int a = Integer.parseInt("123");
-
-
自动装箱和自动拆箱
-
自动装箱:
Integer a = 132; // 默认实现Integer.valueOf(123)
-
自动拆箱:
int b = a; // 默认实现 a.intValue()
-
特别注意:
-
Integer,源码中将[-128,127]存入缓存中,需要时直接调用,不会创建对象,提高性能。
-
超出[-128,127]的值,会 new Integer(值) 创建对象
public class Test { public static void main(String[] args) { Integer n1 = 5; Integer n2 = 5; Integer n3 = 128; Integer n4 = 128; // true : 从缓存中取123,两个值相等 System.out.println(n1 == n2); // false : 创建了两个不同的对象,对象内存地址不同 System.out.println(n3 == n4); } }
-
-
-
基本数据类型、字符串、封装类 转换
-
基本数据类型 – > 字符串
String s = 100 + ""; String s = String.valueOf(100);
字符串 ——> 基本数据类型
int i = Integer.parseInt("100"); int i = Integer.valueOf("100");//先转换成Integer类型,再自动拆箱,给int类型的i变量
-
基本数据类型 – > 封装类
Integer a = 100; // 自动装箱
封装类 ——> 基本数据类型
int b = a; // 自动拆箱
-
2. 引用数据类型
引用数据类型分3种:类,接口,数组 。保存的是对象的内存地址。
- 类引用
- Object o、String s:StringBuffer,StringBuilder、 ArrayList、HashSet、HashMap …
- 接口引用
- List list、Map <K,V> map…
- 数组引用
- char[] c 、int[] i、double[] d …
3. 基本数据类型和引用数据类型的区别
-
存储不同
- 基本类型存储在栈中,存的是值,引用类型存储在堆中,存的是地址。
-
参数传递不同
- 基本类型传值,引用类型传地址。
-
追问: 为什么Java中数据的存放有堆和栈之分?
Java中垃圾回收机制,栈内存中的变量随着方法结束内存自然销毁了。
引用类型存放在堆内存中,是因为**有些引用需要反复使用。**当方法结束的时,引用类型对象不会随方法的结束而销毁,因为它可能被另一个引用类型所应用。只有当一个对象没有任何引用变量的时候,垃圾回收机制才会回收。
3. 方法
1.1 普通方法
-
什么是方法
方法的本质是一个代码片段,它可以完成某种功能,并且可以重复调用。在c语言种,称方法为函数。
-
如何定义一个方法
方法定义在类体中,一个类中可以定义多个方法,但是方法体中,不能再定义方法
[修饰符列表] 返回值类型 方法名(形式参数列表){ 方法体; }
-
如何调用
-
静态方法:static 修饰的方法
- 在同一个类中,方法名(实参) 或者 类名.方法名(实参)
- 不在同一个类,类名.方法名(实参)
-
实例方法:没有static修饰的方法
通过new创建实例对象,再通过实例对象调用方法
引用.方法名(实参)
-
1.2 方法的内存分配
方法执行的时候代码片段存在哪里?方法执行的时候执行过程的内存在哪里分配?
-
方法代码片段属于.class字节码文件一部分,字节码文件在类加载的时候,将其方法加载到了方法区中,所以JVM中的方法区最先获得代码片段。
-
代码片段虽然在方法区内存当中只有一份,但是可以被重复调用。
- 每次调用,需要在栈内存分配执行空间
- 此时,会将方法入栈push,方法执行完后,将方法出栈pop。
- 每次调用,需要在栈内存分配执行空间
- 局部变量在方法体中声明,局部变量在运行阶段在栈中分配。
1.2 构造方法
一、构造方法的特点
(1)每当实例化对象时就会调用构造方法,并初始化对象
(3)两种构造方法:无参数构造方法、有参数构造方法
(3)语法上:与类同名,但没有返回类型
二、什么叫做实例化对象?
- 理解类和对象的含义
- 什么是类?
- 类是一个模板,现实中不存在的类,描述的是对象的共同特征
- 类中包含属性和方法:
- 属性:状态信息,用变量定义
- 方法:动作信息
- 什么是对象?
- 万物皆对象,对象是现实中存在的独立体,它具有自己独特的特征
- 通过new关键字可以在堆内存中开辟一个内存空间,该内存空间叫做对象
- 什么是类?
- 实例化对象
- 具体地将对象创建出来的这个过程,叫做实例化对象
- 通过new关键字创建对象时,会自动调用对象中的构造方法,实例化对象。
4. 面向对象
1.1 面向过程和面向对象的区别
- 面向过程:关注点在于实现的过程
- 优点:能够快速开发业务逻辑简单的程序
- 缺点:耦合度高,扩展能力差,不能复用
- 面向对象:关注点在于对象的功能
- 优点:耦合度低,扩展能力强,组件可以重复调用
- 缺点:前期投入成本高,要从对象中提取抽象概念
【补充】
采用面向对象的方式开发一个软件,生命周期当中:【整个生命周期中贯穿使用OO面向对象方式】
面向对象的分析:OOA
面向对象的设计:OOD
面向对象的编程:OOP
1.2 类和对象的概念和定义
-
什么是类?
-
类是一个模板,现实中不存在的,类描述的是对象的共同特征
-
类中包含属性和方法
- 属性:描述对象的状态信息,通常采用变量方式定义
- 方法:描述对象的动作信息
-
-
什么是对象?
- 对象是独立体,现实中存在,对象具有自己独特的特征
- 通过new可以在堆内存中开辟一个内存空间,该内存空间叫做对象
1.3 面向对象的三大特征
封装、继承、多态
参考链接:https://blog.csdn.net/jianyuerensheng/article/details/51602015
1 封装
1.1 什么是封装?
-
封装从字面意思上理解是包装的意思,可以隐藏信息。
-
封装是指利用抽象的数据类型对数据和数据的基本操作进行包装,使其成为一个不可分割的独立体。
-
对于对象而言,封装的是属性和方法,封装把一个对象的属性私有化,并且对外提供
可以访问属性的接口,因而外部对象无需知道内部细节,可以通过接口来访问该对象。
1.2 封装的作用
-
封装可以隐藏信息,保护底层数据的安全
-
封装可以减少耦合,提高程序的扩展力
-
Java给8种基本树类型提供了对应的封装类,目的是为了解决基本数据类型无法面向对象的问题。
【补充】
开闭原则:OCP
一个软件实体应该对外扩展开放,对修改关闭。
1.3 封装的实现
- 把对象中的属性私有化,并对外提供get和set方法
- get:获取,有返回值类型;set:修改,无返回值类型,但有参数列表
1.4 封装的使用场景
- 集合中的泛型必须要使用封装
- 可以成员变量设置为空【int a; Integer a;】
- 可以描述两种状态:0和空【考试成绩0,和没有参加考试null】
- 可以将字符串解析成基本数据类型【int a = Integer.parseInt(“123”);】
2 继承
2.1 什么是继承?
-
先有父类,再有子类,子类继承父类,子类重写父类的方法
-
父类中的私有的属性以及构造方法不能继承给子类
-
子类有自己的特有的属性和方法,是对父类的扩展
-
子类只能继承一个父类:单继承
-
一个类没有继承父类,默认继承Object类
2.2 继承的作用
-
复用已存在的代码,能够大大的提高开发的效率
-
有了继承才有了以后“方法重写”和“多态机制”
缺点:
-
父类变,子类就必须变 ,尽量不要修改父类中的代码,可以通过子类继承父类,对其扩展
-
继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的
-
继承是一种强耦合关系
-
2.3 继承的实现
继承语法格式:
[修饰符列表] class 类名 extends 父类名{
属性;
方法;
}
2.4 方法重载 与 方法重写
1 方法重载(Overloading)
1.1 什么是方法重载?
-
方法重载是指在同一个类中定义多个同名的方法,但要求每个方法的参数列表不同:数量不同,顺序不同,类型不同。
-
方法重载主要与方法名和参数列表有关,与修饰符列表和返回值类型无关。
-
方法名 + 参数列表是方法的唯一标识:即方法名 + 参数列表相同,则是同一个方法,反之,代表的是不同的方法。
1.2 方法重载的作用?
- 在编写方法时,不用为了不同的参数列表,而写多个方法 ,减少了重复步骤
- 在调用方法时,只需要记住一个方法名即可。根据传入的参数类型不同,自动匹配对应的方法。
1.3 如何实现方法重载?
- 在同一个类中
- 方法名相同
- 参数列表不同:数量不同,顺序不同,类型不同…
2 方法重写(Overriding)
2.1 什么是方法重写?
子类继承父类方法,即子类重写父类的方法:
如果在子类中定义的一个方法,其返回类型、名称、及参数列表正好与父类中某个方法相匹配,那么可以说,子类方法重写了父类方法。
2.2 方法重写的作用?
当父类的方法无法满足业务需求,而我们需要对它的功能进行扩展,但又不能改动它的代码,因此我们可以使用子类继承父类的方法,然后在子类中重写父类的方法,即扩展了父类的功能,又没有修改父类的代码。符合开闭原则(OCP):一个软件实体对扩展开放,而对内修改关闭。
2.3 如何实现方法重写?
-
方法重写发生在具有继承关系的父子类之间
-
子类在方法重写的时候:
- 返回值类型,方法名,形参列表相同;方法体中的内容根据需求修改
- 如果需要父类原有的方法:使用 super() , 调用父类
- 访问权限范围不能缩小,抛出异常不能更多
访问权限 | 同一个类 | 同一个包中的类 | 子类 | 其他包中的类 |
---|---|---|---|---|
public | * | * | * | * |
protected | * | * | * | |
defualt | * | * | ||
private | * |
注:没有public 、protected、private修饰的属性,默认访问权限:defualt
3 多态
3.1 什么是多态?
- 多态是指同一个事物在不同情况下表现出的多种形态
- 多态包括编译时多态和运行时多态
- 编译时多态:父类型的引用指向子类型
- 运行时多态:父类型的引用调用的是子类型的方法
3.2 多态的作用
- 降低程序的耦合度,提高程序的扩展力
- 多态可以让我们不用关心某个对象到底是什么具体类型,可以通过父类型引用来调用该对象的方法,该引用是抽象类或者接口。
3.3 如何实现多态?
-
子类继承父类,子类能够向上转型
-
父类型的引用指向子类型
多态面试题:
public class A {
public int a = 0;
public void fun(){
System.out.println("-----A-----");
}
}
public class B extends A{
public int a = 1;
public void fun(){
System.out.println("-----B-----");
}
public static void main(String[] args){
A classA = new B();
System.out.println(classA.a); //0 : java中变量不能重写
classA.fun(); //B
}
}
解析:
java中变量不能重写,可以按如下口诀记忆:
A classA = new B();
// 左边 = 右边;
变量多态看左边,
方法多态看右边,
静态多态看左边。
1.4 抽象类和接口的区别
-
从定义上:
- 抽象类(abstract): 抽象类是对根源的抽象,表示的是这个对象是什么 , 比如男人是人、女人也是人
- 接口(interface):是一种特殊的抽象类, 接口是对动作的抽象,表示的是这个对象能做什么,比如人可以吃东西
-
从方法上:
- 抽象类和接口都不能直接实例化。
- 抽象类中有构造方法,接口中没有构造方法。
- 抽象类中可以有普通变量和普通方法 ,接口中只能定义常量和抽象方法
-
从继承上:
- 一个类只能继承一个抽象类 ,但是可以实现多个接口
- 类与类之间只能单继承,接口与接口之间支持多继承
抽象方法:
- 抽象类和接口里的抽象方法必须全部被子类所实现:方法重写。
- 如果没有全部实现,那么该子类只能是抽象类。
- 父类中的抽象方法只能声明,不能在父类中实现。
- 抽象类中可以没有抽象方法