1. 认识java
JSE
主要用于编写C/S项目和提供标准的JAVA类库,是所有基于Java语言开发的基础
JME
嵌入式开发,向手机里的软件、掌上电脑等等
JEE
用来构建大型网站和B/S系统 ,作为一个企业版本,主要是给出一个开发企业级应用架构的解决方案,同时给出了在这个架构中相关组件以供开发人员使用
classpath
操作系统利用classpath变量来寻找当前后缀为class的字节码文件所存放的路径,并以最先找到的为准。从JDK1.6开始,不需要手动设置
JAVA_HOME
JAVA_HOME是一个约定,通常它指的是JDK的目录。如果需要JDK的话,大部分程序会默认去环境变量中取JAVA_HOME这个变量。
JVM
JVM是Java Virtual Machine的缩写。它是一种基于计算设备的规范,是一台虚拟机,即虚构的计算机。
JVM屏蔽了具体操作系统平台的信息(显然,就像是我们在电脑上开了个虚拟机一样),当然,JVM执行字节码时实际上还是要解释成具体操作平台的机器指令的。
通过JVM,Java实现了平台无关性,Java语言在不同平台运行时不需要重新编译,只需要在该平台上部署JVM就可以了。因而能实现一次编译多处运行。(就像是你的虚拟机也可以在任何安了VMWare的系统上运行)
JRE
JRE是Java Runtime Environment的缩写,也就是JVM的运行平台,联系平时用的虚拟机,大概可以理解成JRE=虚拟机平台+虚拟机本体(JVM)。类似于你电脑上的VMWare+适用于VMWare的Ubuntu虚拟机。这样我们也就明白了JVM到底是个什么
JDK
Java Develop Kit,Java的开发工具包,JDK本体也是Java程序,因此运行依赖于JRE,由于需要保持JDK的独立性与完整性,JDK的安装目录下通常也附有JRE。目前Oracle提供的Windows下的JDK安装工具会同时安装一个正常的JRE和隶属于JDK目录下的JRE
Java命令
javac 编译源文件生成字节码文件
java 运行字节码文件
javadoc 由源文件中的文档注释生成html文档文件
-d 指定文档生成路径
-encoding 设置文档编码
-charset 设置字符编码
javap 反编译显示类成员变量和成员函数首部
jar 把一些类的字节码文件压缩成一个jar文件
开源JDK
Open JDK https://openjdk.java.net/
Adopt Open JDK https://adoptopenjdk.net/
Amazon Corretto(推荐) https://aws.amazon.com/cn/corretto/
2. Java8新特性
- Lambda表达式:Lambda表达式是一种简洁的语法,用于表示匿名函数。它们可以被视为是一种函数式编程的核心,可以使代码更加简洁和易于阅读。
- Stream API:Stream API提供了一种新的处理集合数据的方式,它可以使代码更加简洁和易于阅读。它可以让你以声明式的方式进行操作,而不是使用迭代器进行循环。
- 新的日期和时间API:Java 8引入了一种新的日期和时间API,它提供了一种更加简单和易于使用的方式来处理日期和时间。它提供了一些新的类,如LocalDate、LocalTime和Instant,以及一些新的方法,如plusDays()和minusHours()。
- 接口的默认方法:Java 8允许接口中包含默认方法,这些方法可以在接口中进行实现。这就使得接口可以更加灵活,可以在不破坏现有实现的情况下进行扩展。
- 方法引用:方法引用是一种简洁的语法,用于表示对方法的引用。它可以使代码更加简洁和易于阅读。
3. 值传递&引用传递
Java中的参数传递方式是值传递。对于对象类型的参数,传递的是对象的引用(内存地址),因此看起来像是引用传递。但实际上,传递的是引用的值,而不是引用本身。因此,在函数或方法中重新赋值对象的引用不会影响到原始值,但对对象内部状态(属性值)的修改会影响到原始值。
3.1. 值传递
值传递是指在函数或方法中,将参数的值复制一份传递给函数或方法。在函数或方法中对参数的修改不会影响到原始值。这种传递方式常见于基本数据类型(例如int、double等)和不可变对象(例如String、Integer等)
例如,以下代码中的swap方法采用的是值传递的方式:
public static void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
}
public static void main(String[] args) {
int x = 10;
int y = 20;
swap(x, y);
System.out.println("x = " + x + ", y = " + y); // 输出 x = 10, y = 20
}
3.2. 引用传递
引用传递是指在函数或方法中,将参数的引用(内存地址)传递给函数或方法。在函数或方法中对参数的修改会影响到原始值。这种传递方式常见于可变对象(例如数组、集合等)。
例如,以下代码中的add方法采用的是引用传递的方式:
public static void add(List<Integer> list, int value) {
list.add(value);
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
add(list, 10);
System.out.println(list); // 输出 [10]
}
4. Java规范
区分大小写
强类型语言
文件名与类名,即main()所在类相同
一个Java文件中只能有一个public类
Java中字符和字符串都用Unicode编码表示
在Unicode编码中一个字符占两个字节
5. Java文件命名
一个Java文件中只能有一个public类
如果文件中只有一个类,文件名必须与类名一致
如果文件中不止一个类,文件名必须与public类名一致
如果文件中不止一个类,而且没有public类,文件名可与任一类名一致
6. 注释
注释一行
//
注释多行
/* */
文档注释
/**
*
*
*/
7. 关键字
关键字的字母全部小写
8. 标识符
包含:类名、变量名、常量名、方法名….
格式:以字母、下划线、$
开始,后面可跟字母、下划线、$
、数字
9. 数据类型
9.1. 基本数据类型
八大基本类型
数值型
整数类型
// 整数默认是int类型,如果数字过大,则必须在末尾加 L 否则会出错
byte
占一个字节,数字大小为 -2^7——2^7-1,默认值为 0
short
占两个字节,数字大小为 -2^15——2^15-1,默认值为 0
int
占四个字节,数字大小为 -2^31———2^31-1,默认值为 0
long
占八个字节,数字大小为 -2^63——2^63-1,默认值为 0L
浮点型
// 实数默认是double类型,如果希望一个实数是float类型,可以在数字后加 F
float
占用四个字节,默认值为 0.0F
double
占八个字节,默认值为 0.0
字符型
// 单引号包裹
char
占两个字节,数字大小为0——2^16-1,是Unicode编码,默认值为 '\u0000'(空字符)
布尔型
boolean
占一个字节,默认值为 false,只有两个值:true和false,且它们不能对应于任何整数值
9.2. 引用数据类型
类、接口、数组
9.3. Java中的引用(重点)
在Java中,引用是指一个对象的内存地址。当创建一个对象时,Java会在堆上为其分配内存,并返回一个引用,该引用指向该对象的内存地址。可以使用该引用来访问该对象
需要注意的是,Java中的引用是强引用。这意味着只要引用存在,垃圾收集器就不会释放该对象的内存。如果程序员不再需要该对象,可以将引用设置为null,这样垃圾收集器就可以释放该对象的内存
9.4. 拓展
特殊字符
反斜线 \\
、退格 \b
、回车 \r
、制表符 \t
、换行 \n
、单引号 '
进制整数
Java中二进制0b开头、八进制0开头、十六进制0x开头
浮点数拓展
BigDecimal类(金融计算常用)
10. 类型转换
10.1. 自动转换
把小容量的类型转换为容量大的类型
如
double a = 10;
10.2. 强制转换
把大容量的类型转换为容量小的类型
如
int a = (int)88.88;
注意
不能对boolean类型进行类型转换
把大容量的类型转换为容量小的类型时,容易缺失精度
整型、实型、字符型数据可混合运算,但要先转换为统一类型,转换从低级到高级(如:byte转int,因为byte占1字节,int占4字节,byte转int不丢失数据)
11. 变量
程序运行过程中,值可以改变的量,实质是内存上的一块空间
数据类型 变量名 = 变量值
如
int a = 3;
类变量
static修饰的变量
实例变量
实例变量,从属于对象,若不对变量进行初始化,则布尔值,默认false,除了基本类型默认值为0,其余的默认值都是null
局部变量
局部变量必须初始化即赋值后才可以使用,如果局部变量未赋值,编译无法通过。
例
public class demo {
// 类变量 static
static int password;
// 实例变量 :从属于对象
String name;
int age;
// main方法
public static void main(String[] args) {
//局部变量
String $_a="asd";
System.out.println($_a);
}
// 其他方法
void func(){
// 局部变量
}
}
12. 常量
初始化后不能再改变值,常量名一般全大写
final 常量名 = 值;
例
final int MAX = 30;
final可以修饰成员方法,成员变量、类
修饰方法
表明方法是最终方法,不能被重写
修饰变量
表明变量是常量,不能再次被赋值
修饰类
表明类是最终类,不能被继承
修饰局部变量
变量是基本类型。表示基本数据类型的数据值不能发送改变
变量是引用类型。表示引用类型的地址值不能发生改变,但是地址里面的内容可以发生改变
13. 运算符
优先级问题
使用括号()
解决优先级问题
13.1. 算术运算符
加+
、减-
、乘*
、除/
运算结果和运算对象的类型有关,若运算对象中有一个是浮点型,则结果也为浮点型,否则为整型
public class AAA {
public static void main(String[] args){
int a = 10;
float b = 3;
int c = 3;
System.out.println(a/b); //结果为 3.3333333
System.out.println(a/b); //结果为 3
}
}
取余%
允许取余运算的被除数和除数是实数,所得的余数的正负只和被除数相同
System.out.println(1%-0.3); //结果为0.10000000000000003
字符的+
操作
拿字符的ASCII码来进行计算
当算术表达式包含多个基本数据类型的时候,整个算数表达式的类型会自动进行提升
byte类型,short类型和char类型都被提升到int类型
整个表达式自动提升到表达式中最高等级操作数同样的类型
字符串的+
操作
当+
操作中出现字符串时,+
表示字符串的连接
"123" + "abc" 结果 "123abc"
当连续进行+
操作时,从左到右逐个执行(可以把非字符串转换成字符串)
"x" + 32 + 1 结果 "x321"
32 + 1 + "x" 结果 "33x"
System.out.print('a' + 1); //结果为 98
System.out.print("" + 'a' + 1); //结果为a1
13.2. 关系运算符
>
、>=
、<
、<=
、!=
、==
13.3. 逻辑运算符
逻辑非!
结果取反
逻辑与&
两边的表达式只要有一个是假的,整个式子就为假,两边都会执行
逻辑或|
两边的表达式只要有一个是真的,整个式子就为真,两边都会执行
13.4. 短路逻辑运算符
短路与&&
左边的表达式为假时,右边的表达式不执行
短路或||
左边的表达式为真时,右边的表达式不执行
13.5. 赋值运算符
不推荐使用
=
、+=
、*=
、/=
、%=
扩展的赋值运算符,隐含了强制类型转换
13.6. 自增自减运算符
不推荐使用
++
、--
如果放在变量前,就先执行自增或自减,然后变量才参与其他操作
++a,就先执行 a = a + 1,之后再执行其他操作
如果放在变量后,变量先参与其他操作,然后执行自增或自减
a++,就先执行操作,之后再执行 a = a + 1
例
int a=1;
int b = ++a;
System.out.println(b); //结果为2
int a=1;
int b = a++;
System.out.println(b); //结果为1
13.7. 三元运算符
关系表达式?表达式1:表达式2;
如:a > b ? a : b;
规则:
首先计算表达式的值
如果值为true,表达式1的值,为运算结果
如果值为false,表达式2的值,为运算结果
13.8. 位运算符
位运算效率高
按位与&
:把两个数的二进制位相与
1 & 1 = 1
1 & 0 = 0
0 & 0 = 0
0 & 1 = 0
按位或|
:把两个数的二进制位相或
1 | 1 = 1
1 | 0 = 1
0 | 0 = 0
0 | 1 = 1
按位取反~
:把一个数字的二进制位取反
~1 = 0
~0 = 1
按位异或^
:把两个数的二进制位异或
1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0
右移>>
:右移运算符,num » 1,相当于num除以2。当为正数时,前面补0,为负数时,前面补1
无符号右移>>>
:忽略符号位,空位都以0补齐
左移<<
:左移运算符,num « 1,相当于num乘以2。无论正负数,后面补0
14. Java包
package语句作为Java源文件的第一条语句,指明该源文件定义的类所在的包
本质就是文件夹,对类进行分类管理
// 一般利用公司域名倒置作为包名
package 包名;
例
package sunrise; //可以是合法标识符
package com.baidu.www; //可以是若干标识符由`.`号分割
注意
类中的package命令不是非得放在类的第一行,其上可以写注释和空行,但是对于import、类、变量等命令,则一定不能放在package命令之上
导包
import 包名;
引入包中所有类,用import 包名.*;
引入包中某个类,用import 包名.类名;
权限
修饰符 | 同包同类 | 同一个类中,子类无关类 | 不同包的子类 | 不同包的无关类 |
---|---|---|---|---|
private | 可以 | |||
默认 | 可以 | 可以 | ||
protected | 可以 | 可以 | 可以 | |
public | 可以 | 可以 | 可以 | 可以 |
15. Scanner类
public class demo {
public static void main(String[] args) {
// 创建 Scanner 对象
Scanner scanner = new Scanner(System.in);
// 判断是否输入字符串
if (scanner.hasNext()){
// 使用next方法接收
String str = scanner.next();
System.out.println(str);
}
// 关闭io流
scanner.close();
}
}
15.1. Scanner的方法
nextByte()
方法用来读取用户输入的byte数据, hasNextByte()
方法用来判断用户输入的数据类型是否为byte
这些方法执行时都会堵塞,等待输入回车确认
获取数据 | 判断数据 |
---|---|
nextByte() |
hasNextByte() |
nextDouble() |
hasNextDouble() |
nextFloat() |
hasNextFloat() |
nextInt() |
hasNextInt() |
nextLine() |
hasNextLine() |
nextLong |
hasNextLong() |
nextShort |
hasNextShort() |
next()不会吸取字符前/后的空格/Tab键,只吸取字符,开始吸取字符(字符前后不算)直到遇到空格/Tab键/回车截止吸取
nextLine()吸取字符前后的空格/Tab键,回车键截止
15.2. 格式化输出
输出控制符 | 针对的数据类型 |
---|---|
%d | int,long int,short,byte |
%x,%X,%#x,%#X | int,long int |
%c | char |
%f | float,double |
%m.nf | 输出的数占m列,小数点后保留n位 |
%s | String |
System.out.printf("Name: %s, Age: %d, Salary: %.2f%n", name, age, salary);
使用 String.format 进行格式化输出
String formattedString = String.format("Name: %s, Age: %d, Salary: %.2f%n", name, age, salary);
System.out.print(formattedString);
注意
%x和%X的区别是显示十六进制数a-f的大小写
%x和%#x的区别是显示或不显示0x前缀
三种输出
System.out.print() //一般的标准输出,不换行
System.out.println() //一般的标准输出,换行
System.out.printf() //格式化输出,不换行
占位符
System.out.print("插入 {} 条题目执行时长:{}", questionInfoVoList.size(), stopWatch.getTotalTimeMillis());
16. 流程控制
16.1. 顺序
16.2. 选择
if、else if、else、switch
16.3. 循环
while、do while、for
增强for循环
简化数组和Collection集合的遍历
实现Iterable接口的类允许其对象成为增强型for语句的目标
for(元素类型 变量名 : 数组或Collection集合){
在此处使用变量即可,该变量就是元素
}
例
class work{
public static void main(String[] args) {
List<String> c = new ArrayList<String>();
c.add("hello");
c.add("java");
c.add("hello");
for (String s:c){
System.out.println(s);
}
注意
continue,结束本次循环,开始下一次循环
break,停止循环
if、while、for中进行真假判断时,只能使用逻辑表达式
17. 方法
具有独立功能的代码块
17.1. 定义
//方法头
修饰符 返回值类型 方法名(参数类型 参数名){
//方法体
return 参数;
}
如
public static void test(){
...
...
}
注意:方法不能嵌套定义
17.2. 方法调用
方法名()
17.3. 参数
形参、实参、可变参数
可变参数
方法声明时,在指定参数类型后加一个省略号(...)
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它
之前声明。
例
public void firstTest(char s,int ...i) { // i 就是可变参数
if (i.length > 0) {
System.out.println(i[0]);
}
}
17.4. 方法重载
同一个类中的多个方法只有参数列表不同
/*
多个方法在同一个类中
多个方法具有相同的方法名
多个方法的参数不同(参数类型不同或数量不同)
只与参数列表有关,与返回值无关
*/
import java.util.*;
class a{
int jiafa(int c,int d){
return c + d;
}
int jiafa(int c,int d,int e){
return c + d + e;
}
}
class test {
public static void main(String[] args) {
a A = new a();
System.out.printf("%d\n",A.jiafa(1,2));
System.out.printf("%d\n",A.jiafa(1,2,3));
}
}
18. 数组
18.1. 声明&创建
// 声明数组变量
int[] boys; //推荐
或
int boys[];
// 使用new来创建数组
boys = new int[10];
18.2. 初始化
动态初始化
初始化时,只指定数组长度,具体值由系统分配默认值
int[] boy = new int[3];
静态初始化
初始化时,只指定数组元素的具体值,无需指定数组的长度,由系统决定数组长度
int[] boy = new int[]{1,2,3,4,5,6};
或
int[] boy = {1,2,3,4,5,6};
18.3. 访问数组
使用索引访问数组中的元素,索引从0开始
18.4. 特点总结
数组变量属引用类型
数组中的元素可以是任何数据类型,包括基本类型和引用类型。
数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型,数组对象本身是在堆中的。
18.5. 数组的使用
获取数组的大小
数组名.length
数组作为返回值
return 数组变量;
18.6. Arrays类
打印数组元素,toString
排序数组元素,sort
给数组赋值,fill
比较数组中元素的值,equals
查找数组元素,binarySearch,通过binarySearch方法能对排序好的数组进行二分查找法操作
18.7. 常见问题
索引越界
空指针异常
19. 对象数组
使用基本数据类型的类创建数组,数组中的每个元素是对象
声明
A m1,m2,m3;
//等价于
A [] m = new A[3];
创建
package Test;
class A{
A(int a){
System.out.printf("%d\n",a);
}
}
public class work {
public static void main(String[] args) {
A [] m = new A[3];
m[0] = new A(2);
m[1] = new A(3);
m[2] = new A(4);
for (int i=0;i<=2;i++){
System.out.println(m[i]);
}
}
}
20. 类和对象
20.1. 类的三大特性
- 封装
- 继承
- 多态:操作多态、继承多态
20.2. 类的构成
把一类事物的静态属性和动态可以执行的操作组合在一起所得到的就是类
public class Car{
//成员变量
int high;
// 方法
public void run(){
// 局部变量
int speed = 80;
System.out.println("hello world");
}
}
成员变量
- 类中方法之外的变量
- 位于堆内存
- 若不赋值,则是该类型的初始值(eg:int 为0,Integer 为 null)
- 伴随对象的产生和消亡
- 成员变量可以是Java允许的任何数据类型
局部变量
- 类中方法内或方法声明上的变量
- 位于栈内存
- 必须先赋值,才能使用
- 伴随方法的产生和消亡
方法
静态方法(static修饰的)
非静态方法(不加static关键字的方法,在类定义时没有占用内存,只有在类被实例化成对象时,对象调用该方法才被分配内存)
注意:一个Java文件中只能有一个main方法
20.3. 类的访问控制
权限大小:私有< 默认< 保护< 公有
在同一个类中,可以访问该类中的所有修饰符。而在其他类中,只能访问公共(public
)成员
default
(默认):如果没有明确指定访问修饰符,则使用默认修饰符。默认修饰符的访问权限是包级别的,它允许同一个包中的其他类访问。public
:public
修饰符表示公共访问权限,可以在任何地方访问该类、方法或属性,包括其他包中的类。protected
:protected
修饰符表示受保护的访问权限,它允许同一个包中的其他类以及其他包中的子类访问该类、方法或属性。子类可以继承并访问父类中的protected
成员。private
:private
修饰符表示私有访问权限,只允许在同一个类中访问该类、方法或属性。其他类无法直接访问私有成员。
注意
在类的内部,所有成员可以互相访问,访问控制符是透明的。访问控制符是针对外部访问而言的
外部访问的方式
- 通过类名
- 通过类对象名
- 通过子类访问
20.4. 类的构造方法
类在创建时,该方法自动调用,用来给所创建的对象一个初始状态,IDEA右键 generate –> constructor快速生成构造方法
注意:类中有构造方法才能被实例化。若不创建构造方法,则java会默认创建一个无参的构造方法。一旦定义了有参构造,无参构造就必须显示定义。构造方法名字必须与所在类的名字一样。构造方法没有返回值类型,也不能写void。一个类中可以有多个构造方法。构造方法可以有参也可以无参
class A{
int i;
int j;
A() {}
A(int c, int d){ //有参构造方法
i = c;
j = d;
}
}
20.5. 一个标准的类
成员变量(使用private修饰)
构造方法(提供一个无参构造方法、提供有参构造方法)
成员方法(提供每一个成员变量对应的setXxx()、getXxx()、提供一个显示对象信息的toString())
创建对象并为其成员变量赋值的两种方式:
- 无参构造方法创建对象后使用setXxx()赋值
- 使用带参构造方法直接创建带有属性值的对象
class Student{
// 成员变量
private String name;
private int age;
//无参构造方法
public Student(){};
//有参构造方法
public Student(String name,int age){
this.name = name;
this.age = age;
}
//成员方法
public void setName(String name){
this.name = name;
}
public String getName(){
return name;
}
public void setAge(int age){
this.age = age;
}
public int getAge(){
return age;
}
public void toString(){
System.out.println(name + "," + age);
}
}
20.6. 对象
类的实例化结果是一个具体的实体
对象的引用
用类创建一个对象时,对象中就存放着引用(指向对象实体的一个地址),如果两个对象有相同的实体就有相同的引用
对象的实体
用类创建一个对象时,成员变量被分配内存空间,,这些内存空间就是对象的实体
class A{
int j;
int i;
}
class test{
public static void main(String[] args){
A aa = new A(); //new A(),在堆中动态分配一块区域,被当作了A的对象实体
//aa本身的内存是在栈中分配的
//堆中内存的地址赋给了aa
//aa指向堆中的内存,aa代表了堆中的内存
aa.j; //aa.i代表aa这个静态指针变量所指向的动态内存中的A对象
aa.i;
}
}
注意:如果类中没有带参构造方法,或者类中没有成员变量对应的setXxx()函数,那么创建的对象将无法修改类中定义的成员变量的值,则该对象的成员变量的值和类中成员变量的值始终是一致的
20.7. 对象的组合
一个类把对象作为自己的成员变量,那么创建对象时,该对象中就会有其他对象
//该例子中,b类将a类对象作为自己的成员变量
class a{
int aa = 11;
}
class b{
int bb = 45;
a group = new a(); // a类对象
}
public class work {
public static void main(String[] args){
b li = new b();
System.out.println(li.group.aa);
}
}
20.8. this
谁最终调用函数,this就指向谁,this指向的是正在运行当前代码的那个对象
静态函数(static修饰的)内部没有this指针
用法
通过类名,new出一个对象的过程,叫做”类的实例化”。类中的this会在实例化的时候指向新new出的对象。所以,this.属性、 this.方法 实际上是将属性和方法绑定在即将new出的对象上面
- this.成员变量 , 访问本类的成员变量
- this.成员方法(), 访问本类成员方法
class A{
int x = 10;
void num(int x){
System.out.printf("%d\n",this.x);
System.out.printf("%d\n",x);
}
}
public class test{
public static void main(String[] args){
A a = new A();
A b = new A();
a.num(2);
b.num(3);
}
}
/**结果
10
2
10
3
*/
注意
当局部变量和成员变量同名的情况下必须使用this指定成员变量的变量名。如果二者名称不同,系统会自动隐含一个this,可以不写(建议写明)
20.9. static
static声明了属性和方法是属于类本身的,不创建对象也可以直接访问(前提是非私有)
static 修饰的属性、方法伴随类一起加载
非静态方法可访问静态方法,而静态方法不能访问非静态
静态代码块
// 最先执行,且只执行一次
static{
}
静态导入包
import static java.lang.Math.random;
import static java.lang.Math.PI;
20.10. Class vs Object in Java
| Aspect | Class | Object | | —— | ———————————————————– | ————————————————————– | | 定义 | 类是用于创建对象的模板 | 对象是类的特定实例 | | 语法 | 使用 Class关键字声明 | 使用new关键字和类构造函数创建 | | 目的 | 定义对象的结构和行为 | 基于类创建真实的实体 | | 使用 | 包含由类的所有实例共享的类变量(字段)和方法 | 具有自己属性值的唯一实例,并且可以调用类中定义的方法 | | 例子 | public class Car { // Class variables and methods go here } | Car myCar = new Car(); // Creates an instance of the Car class | | 内存分配 | 类定义存储在JVM的方法区域中 | 对象在运行时在堆中动态分配内存 | | 访问控制 | public, private, or protected | 在其声明的范围内访问 | | 生命周期 | 存在于程序的整个执行过程中 | 由JVM的垃圾收集器创建、使用并最终销毁 |
21. 封装
高内聚,低耦合
将信息隐藏在类的内部,不允许外部程序直接访问,而是通过该类提供的public方法来实现对隐藏信息的访问和操作成员变量
eg:在Java Bean中使用setXxx()、getXxx()操作成员变量
22. 继承
- 子类(派生类)、父类(基类)
- JAVA中类只有单继承,没有多继承,即一个类只能有一个父类
- Java可以有多重继承,即一个类可以继承某一个类的子类
- 子类可以继承父类的非私有属性和方法,但私有的数据或函数,可以通过可继承的函数set、get间接的去访问(重点)
- Java中子类名的特点,子类名都以其父类名作为子类名的后缀,如 FileOutputStream(子类)OutputStream(父类)
22.1. Object类
Object类是Javajava.lang
包下的核心类,是所有类的父类,创建一个类的时候如果没有明确的继承一个父类的话,那么它就是Object的子类
//二者等价
class Person { }
class Person extends Object { }
22.2. extends
子类名 extends 父类名
class family{
int math = 1;
String name = "张三";
}
class A extends family{ //继承于父类family
int high = 180;
}
public class test {
public static void main(String[] args) {
A a = new A();
System.out.printf("%d,%s\n",a.math,a.name); //访问的是父类中的成员变量
}
}
22.3. 变量访问的特点
在子类中访问一个变量,先在子类局部范围找,然后再到子类成员中找,最后到父类成员中找
class family{
int math = 1;
int high = 170;
String name = "张三";
}
class A extends family{ //继承于父类family
int math = 2;
String name = "赵四";
}
public class work {
public static void main(String[] args) {
A a = new A();
System.out.println(a.math + a.name + a.high); //子类中找不到high变量,所以是父类中的high变量
}
}
/*结果是
2赵四170
*/
22.4. 构造方法的访问特点
子类不继承父类的构造方法
子类中的构造方法默认都会访问父类中的无参的构造方法。因为子类继承父类的数据,可能会使用父类的数据,所以在子类初始化前,一定先初始化父类
每个子类的构造方法的第一条默认语句都是super(),即父类的无参构造方法
22.5. 成员方法的访问特点
通过子类对象访问一个方法,先在子类局部范围找,然后再到子类成员中找,最后到父类成员中找
package Test;
class family{
void mc(){
System.out.println("这是父类");
}
}
class A extends family{ //继承于父类family
void mb(){
System.out.println("这是子类");
}
}
public class work {
public static void main(String[] args) {
A a = new A();
a.mc();
}
}
/*
结果是
这是父类
*/
22.6. 子类访问父类的方式
- 在子类内部访问父类成员
- 通过子类对象名访问父类成员
- 通过子类的类名访问父类成员
22.7. super
代表父类对象引用
用法
子类使用super调用父类的构造方法或子类使用super调用被子类隐藏的成员变量和方法
super.成员变量,访问父类成员变量
super(参数),访问父类的构造方法(只能在子类的构造方法里调用)
super.成员方法,访问父类成员方法
注意
子类无法直接继承父类的构造方法,只能通过super语句
如果在子类的构造方法中,显示的写出了super语句,必须保证,该语句是第一条语句,否则出错
例
class family{
public int i;
public int j;
family(int i,int j){
this.i = i;
this.j = j;
}
}
class A extends family{
public int c;
A(int i,int j,int c){
super(i,j); //调用父类的构造方法
//family(i,j); //直接调用父类的构造方法是错的
this.c = c;
}
}
public class test {
public static void main(String[] args) {
A a = new A(1,2,3);
System.out.printf("%d,%d\n",a.c,a.i);
}
}
/*结果是
3,1
*/
22.8. 成员变量隐藏
子类中定义的成员变量只要和父类中的成员变量同名(类型可以相同也可以不同),则子类会隐藏父类的同名变量。被隐藏的父类变量,在子类中可以使用super
关键字引用
class family{
int math = 1;
int high = 170;
}
class A extends family{ //继承于父类family
String math = "2"; //隐藏了父类的 int math
int high = 180; // 隐藏了父类的 int high
void show(){
System.out.println(this.math + " " + this.high); // 2 180
System.out.println(super.math + " " + super.high); // 1 170 通过super访问被隐藏的父类变量
}
}
public class work {
public static void main(String[] args) {
A a = new A();
a.show();
}
}
22.9. 方法的重写
在子类中重新定义父类的方法
条件
有子类、父类的继承关系
子类只能重写父类中的非静态方法
在子类中重写父类的方法时,子类方法的权限不能低于父类,父类的私有方法不能被重写,static、final修饰的方法也不能重写
子类方法抛出的异常范围必须低于父类方法
重写的方法,必须和被重写的方法具有相同的名称、参数列表、返回值类型(即除了方法体,其余必须相同)
例
class family{
int math = 1;
int high = 170;
void pou(){
System.out.println("这是被重写的方法");
}
}
class A extends family{ //继承于父类family
String math = "2";
int high = 180;
void pou(){ //重写父类中的pou()方法
System.out.println("这是重写后的方法");
}
}
public class work {
public static void main(String[] args) {
A a = new A();
a.pou();
// 父类的引用指向子类
// // 对象能执行哪些方法,主要看对象左边的类型
family f = new A(); //子类重写了父类的方法
f.pou();
}
}
23. 多态
Java 的多态是指同一个类的对象在不同情况下表现出来的不同行为和状态。即一个父类可能有若干子类,各子类实现父类方法有多种多样,调用父类方法时,父类引用变量指向不同子类实例而执行不同方法,这就是所谓父类方法是多态的。
23.1. 条件
多态的前提条件有三个:
- 子类继承父类
- 子类重写父类的方法
- 父类引用指向子类的对象
23.2. 类型转换
对象 instanceof 类
当左面的对象是右面的类创建的对象时,该结果 true,否则为false
public class work {
public static void main(String[] args) {
A a = new A();
System.out.println(a instanceof A); //结果为true
}
}
父转子
强制转换
Father f1 = new Son();
// 强制转换
Son f2 = (Son) f1;
注意:
强制转换后,可调用子类独有的方法
子转父
父类的引用指向子类
Father f1 = new Son();//编译看左边,执行看右边
23.3. 多态的形式
通过实现类对象实例化,叫接口多态
多态的形式:具体类多态,抽象类多态,接口多态
多态的前提:有继承或实现关系,有方法重写,有父(类/接口)引用指向(子/实现)类对象
24. Object类详解(重点)
Object类是类层次结构的根,每个类都可以将Object作为超类,所有类直接或间接继承自该类
24.1. ==
运算符
- 既可以判断基本类型,又可以判断引用类型
- 如果判断基本类型,判断的是值是否相等
- 如果判断引用类型,判断的是地址是否相等,即判定是不是同一个对象
24.2. equals
- equals是Object类中的方法,只能判断引用类型
- equals 默认判断的是地址是否相等,子类中往往重写该方法,用于判断内容是否相等。比如Integer、String
自定义类中如何重写equals
可参考String类中对equals的重写方式
24.3. hashCode
- 提高具有哈希结构的容器的效率
- 两个引用,如果指向的是同一个对象,则哈希值是一样的
- 两个引用,如果指向的是不同对象,则哈希值是不一样的
- 哈希值主要是根据地址来的,但是哈希值不等价于地址(哈希值是将对象的内部地址转换为整数来实现,因为Java程序运行在Java虚拟机中)
- 在集合中往往会重写hashCode
24.4. toString
- 默认返回:
全类名+@+哈希值的十六进制
,子类往往重写toString方法,用于返回对象的属性信息 - 重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString形式
- 当直接输出一个对象时,toString方法会被默认的调用
24.5. finalize
- 当对象被回收时,系统自动调用该对象的finalize方法。子类可以重写该方法,做一些释放资源的操作
- 什么时候被回收:当某个对象没有任何引用时,则jvm就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁该对象前,会先调用finalize方法。不是立即回收而是有一套垃圾回收算法
- 垃圾回收机制的调用,是由系统来决定,也可以通过System.gc()主动触发垃圾回收机制
- 可以重写finalize方法,写自己的业务逻辑代码(比如释放资源、数据库连接、或者打开文件)
实际开发中用的少,几乎不用
25. 抽象类和方法
抽象类是对事物的抽象
抽象类和抽象方法必须使用 abstract 修饰
25.1. 抽象方法
没有方法体的方法
public abstract void show();
25.2. 抽象类
不能new 抽象类,只能靠子类去实现它
若类中有抽象方法,则该类必须定义为抽象类
抽象类中可以写普通的方法
抽象类中的方法,应由子类实现。但如果子类也是抽象类,则不必实现
//重写抽象类中的方法,通过子类对象实例化来实现抽象类实例化
public abstract class Animal{
public abstract void eat();
public void sleep(){
System.out.println("睡觉");
}
}
class Cat extends Animal{
public void eat(){ //重写抽象类中的方法
System.out.println("吃鱼");
}
}
class demo{
public static void main(String[] args){
// Animal a = new Animal(); //抽象类不能实例化
Animal a = new Cat(); //多态实现实例化
a.eat();
}
}
//子类是抽象类
public abstract class Animal{
public abstract void eat();
public void sleep(){
System.out.println("睡觉");
}
}
abstract class Cat extends Animal{ //子类定义为抽象类
}
class demo{
public static void main(String[] args){
}
}
25.3. 抽象类的成员
成员变量
常量或变量
构造方法
有构造方法但是不能实例化,作用是用于子类访问父类数据的初始化
成员方法
可以有抽象方法,限定子类必须完整某些动作。也可以有非抽象方法,提高代码的复用性
25.4. 抽象类名作为形参和返回值
方法的形参是抽象类名,方法的返回值是抽象类名,它们都对应该抽象类的子类对象
26. 接口
接口是对行为的抽象
可以把接口理解为提供了一系列功能列表的约定,接口本身不提供功能,它只定义行为。但是谁要用,就要先实现我,遵守我的约定,然后再自己去实现我约定的功能
public interface StudentService {
public void getStudent();
public String getStudentById(int id);
public void setStudentName(String name);
}
26.1. 接口特点
public interface 接口名{}
接口用 interface 修饰
接口没有构造方法,所以接口不能实例化
接口中的所有定义其实都是抽象的 public abstract
26.2. 接口实现类
用 implements 表示,通过类来实现接口
implements可以实现多个接口
接口实现类中需要重写接口中的所有方法,若该实现类是抽象类则不用
public class 类名 implements 接口1,接口2{}
例
//重写接口中的抽象方法
public interface Jumpping { //创建一个接口
public abstract void jump();
}
class Cat implements Jumpping{ //用类实现一个接口
public void jump() { //重写接口中的抽象方法
System.out.print("猫");
}
}
class demo{
public static void main (String[] args){
Jumpping j = new Cat(); //编译看左边,执行看右边
j.jump();
}
}
//接口实现类是抽象类
public interface Jumpping { //创建一个接口
public abstract void jump();
}
abstract class Cat implements Jumpping{ //抽象类
}
class demo{
public static void main (String[] args){
}
}
26.3. 接口的成员
成员变量
只能是常量,默认修饰符是public static final
构造方法
接口没有构造方法,因此接口不能实例化
成员方法
只能是抽象方法,默认修饰符是 public abstract
26.4. 接口名作为形参和返回值
方法的形参是接口名,方法的返回值是接口名,它们都对应该接口的实现类对象
27. 类&接口的关系
27.1. 类和类的关系
类 extends 类
继承关系,只能单继承,但是可以多层继承
27.2. 类和接口的关系
类 implements 接口
实现关系,可单实现,也可以多实现,还可以在继承一个类的同时实现多个接口
27.3. 接口和接口的关系
继承关系,可以单继承,也可以多继承
28. 抽象类&接口的区别
| | 成员区别 | | ———- | ——————————————– | | 抽象类 | 变量、常量、有构造方法、抽象方法、非抽象方法 | | 接口 | 常量、抽象方法 | | | 关系区别 | | 类与类 | 继承、单继承 | | 类与接口 | 实现、单实现、多实现 | | 接口与接口 | 继承、单继承、多继承 | | | 设计理念区别 | | 抽象类 | 对类抽象,包括属性、行为 | | 接口 | 对行为抽象,主要是行为 |
29. 内部类
就是在一个类中定义一个类
内部类分为成员内部类、局部内部类、匿名内部类和静态内部类
class Outer {
class Inner {
// 定义了一个Inner Class
}
}
29.1. 匿名内部类
匿名内部类是我们平常用得最多的,尤其是启动多线程的时候,会经常用到,并且 IDE 也会帮我们自动生成。
前提:存在一个类或接口,这里的类可以是具体的类,也可以是抽象类
本质:是一个继承了该类或实现了该接口的子类匿名对象
public class ThreadDemo {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
t.start();
}
}
匿名内部类是唯一一种没有构造方法的类
匿名内部类的作用主要是用来继承其他类或者实现接口,并不需要增加额外的方法,方便对继承的方法进行实现或者重写
30. 枚举
为了间接表示一些固定的值,Java提供了枚举(Enum),它是指变量的值一一列出来,变量的值只限于列举出来的值的范围内
利用枚举,我们可以清晰地表达代码中的常量,使代码更为可读、可维护
// 定义一个枚举类,用来表示春、夏、秋、冬这四个固定值
public enum Season {
SPRING,
SUMMER,
AUTUMN,
WINTER;
}
30.1. 枚举类的特点
- 所有枚举类都是Enum的子类
- 可以通过
枚举类名.枚举项名称
访问指定的枚举项 - 每一个枚举项实际上就是该枚举的一个对象
- 枚举类也是一个类,可以定义成员变量
- 枚举类的第一行上必须是枚举项,最后一个枚举项后的分号可以省略,但如果枚举类有其他内容,分号不能省略,建议不要省略
- 枚举类可以有构造器,但必须是private的,它默认也是private的
- 枚举类可以有抽象方法,但枚举项必须重写该方法
- 枚举不可以继承
- 枚举其实就是特殊的常量类
30.2. 枚举的方法
方法名 | 说明 |
---|---|
String name() | 获取枚举项的名称 |
int ordinal() | 返回枚举项在枚举类中的索引值 |
int compareTo(E o) | 比较两个枚举项,返回的是索引值的差值 |
String toString() | 返回枚举常量的名称 |
static <T> T valueOf(Class<T> type, String name) |
获取指定枚举类中指定名称的枚举值 |
values() | 获得所有的枚举项 |
public enum NodeEnum{
// 枚举项1
CUSTOMER(11147,"formtable_19","hcdz","xdfly"),
// 枚举项2
SUPPLIER(10799,"formtable20","hcdz","xdfly"),
// 枚举项3
SALENOTE(11107,"formtable97","hcdz","sjly");
// 构造函数
NodeEnum(Integer nodeId, String tableName, String backFieldName, String fromFieldName) {
this.nodeId = nodeId;
this.tableName = tableName;
this.backFieldName = backFieldName;
this.fromFieldName = fromFieldName;
}
/**
* 节点id
*/
private Integer nodeId;
/**
* 表名称
*/
private String tableName;
/**
* 回传地址字段名
*/
private String backFieldName;
/**
* 来源标志字段名
*/
private String fromFieldName;
public Integer getNodeId() {
return nodeId;
}
public String getTableName() {
return tableName;
}
public String getBackFieldName() {
return backFieldName;
}
public String getFromFieldName() {
return fromFieldName;
}
/**
* 根据节点id获取对应的枚举值
* @param nodeid
* @return
*/
public static Map<String,Object> nodeIdOf(int nodeid){
Map<String,Object> map = new HashMap<String,Object>();
for(NodeEnum nodeEnum : values()){
if(nodeEnum.getNodeId().equals(nodeid)){
map.put("tableName", nodeEnum.getTableName());
map.put("fromFieldName", nodeEnum.getFromFieldName());
map.put("backFieldName", nodeEnum.getBackFieldName());
map.put("success", true);
return map;
}
}
map.put("success", false);
return map;
}
}
31. 基本数据类型的包装类
数据类型 | 类包装 |
---|---|
byte | Byte |
int | Integer |
short | Short |
long | Long |
float | Float |
double | Double |
char | Character |
基本数据类型和其对应的包装类在初始化值方面的区别
基本数据类型的包装类在未显式赋值时,会有一个特殊的默认值 null
,表示它们没有被初始化
在使用包装类时,如果没有显式地给它们赋值,在使用时可能会遇到 NullPointerException(空指针异常)的情况
31.1. int和String转换
int转String
返回int参数的字符串表示形式
public static String valueOf(int i)
String转int
将数字的字符串形式转为int类型,是Integer类中的方法
public static int parseInt(String s)
31.2. Character类常用方法
isDigit(char ch)//判断数字字符
isLetter(char ch)//判断字母字符
isLetterOrDigit(char ch)//判断数字字符或字母字符
isLowerCase(char ch)//判断小写字母字符
isUpperCase(char ch)//判断大写字母字符
toLowerCase(char ch)//转为小写形式
toUpperCase(char ch)//转为大写字符
isSpaceChar(char ch)//判断空格
32. 大数的处理
BigInteger 适合保存比较大的整型
BigDecimal 适合保存精度更高浮点型(金融中常用)
33. 常用类
33.1. Math类
Math类里面提供的基本上都是基础的数学公式
33.2. Random类
产生一个随机数。此外任何随机的操作都可以利用Random来处理
Random random = new Random();
int t = random.nextInt(10); //在范围 0 - 9 之间获取一个随机数
33.3. System类
方法名 | 说明 |
---|---|
public static void exit(int status) | 终止当前运行的Java虚拟机 |
public static long currentTimeMillis() | 返回当前时间,毫秒为单位 |
class work{
public static void main(String[] args) {
System.exit(0); // 直接退出虚拟机
System.out.println("123"); //该语句不执行
}
}
33.4. Arrays类
包含用于操作数组的各种方法
方法名 | 说明 |
---|---|
public static String toString(int[] a) | 返回数组的内容的字符串表示形式 |
public static void sort(int[] a) | 按数字顺序排列数组 |
class work{
public static void main(String[] args) {
int a [] = {4,5,2,3,1};
System.out.println(Arrays.toString(a)); //[4, 5, 2, 3, 1]
Arrays.sort(a);
System.out.println(Arrays.toString(a)); //[1, 2, 3, 4, 5]
}
}