java基础
java基础
Java开发规范参见Java开发手册(嵩山版)免费在线阅读_藏经阁-阿里云开发者社区 (aliyun.com)
概述 (Java SE 17 & JDK 17) (oracle.com)
注释
-
单行注释
// 快捷键: ctrl + /
-
多行注释
/* */ 快捷键:ctrl + shift + /
-
文档注释
/** */ javadoc-Java API 文档生成器 (oracle.com)
标识符
java中标识符是为方法、变量或其他用户定义项所定义的名称。
标识符由数字(0 ~ 9)和字母(az和AZ)、美元符号($)、下划线(__)以及Unicode字符集中符号大于0xC0的所有符号组合构成(各符号之间没有空格)
- 标识符的第一个符号为字母、下划线和美元符号,后面可以是任何字母、数字、美元符号或下划线
- Java区分大小写,
- 不能使用数字开头
- 不能使用任何Java关键字作为标识符,标识符可以包含关键字,但不能与关键字重名
- 不能赋予标识符任何标准的方法名
标识符分为两类,分别为关键字和用户自定义标识符。
-
关键字是有特殊含义的标识符,如 true、false 表示逻辑的真假。
-
用户自定义标识符是由用户按标识符构成规则生成的非保留字的标识符,如 abc 就是一个标识符。
关键字
关键字(或者保留字)是对编译器有特殊意义的固定单词,不能在程序中做其他目的使用。关键字具有专门的意义和用途,和自定义的标识符不同,不能当作一般的标识符来使用
Java 的关键字对 Java 编译器有特殊的意义,它们用来表示一种数据类型,或者表示程序的结构等。保留字是为 Java 预留的关键字,它们虽然现在没有作为关键字,但在以后的升级版本中有可能作为关键字
Java 语言目前定义了 51 个关键字,这些关键字不能作为变量名、类名和方法名来使用。以下对这些关键字进行了分类。
-
数据类型:boolean、int、long、short、byte、float、double、char、class、interface
-
流程控制:if、else、do、while、for、switch、case、default、break、continue、return、try、catch、finally
-
修饰符:public、protected、private、final、void、static、strict、abstract、transient、synchronized、volatile、native
-
动作:package、import、throw、throws、extends、implements、this、supper、instanceof、new
-
保留字:true、false、null、goto、const
数据类型
-
强类型语言
要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用
-
弱类型语言
-
Java的数据类型分为两类
- 基本数据类型
- 引用类型
注: *Long类型要在数字后面加个L
*Float类型要在数字后面加个F
*Boolean类型占一位,即1bit
字节
- 位(bit):是计算机内部数据储存的最小单位,11001100是一个八位二进制数
- 字节(byte):是计算机中数据处理的基本单位,习惯上用大写B来表示
- 1B(byte,字节) = 8bit(位)
- 字符:是指计算机中使用的字母、数字、字和符号
- 1bit表示1位
- 1Byte表示一个字节 1B = 8b
- 1024B = 1KB
- 1024KB = 1M
- 1024M = 1G
数据转换
数据类型的级别/优先级/大小排序:
低 --------------------------------------------------> 高 |
强制类型转换(优先级高 -> 低)
强制类型转换格式:(类型)变量名,比如:
//强制类型转换 (类型)变量名 优先级高 -> 低 |
自动类型转换(优先级低 -> 高)
自动类型转换不需要添加任何东西可以直接转换,拿上面的byte b
举例:
//自动类型转换 优先级低 -> 高 |
变量
- 局部变量—必须声明和初始化值(方法内)
- 实列变量— 不自行初始化,则为变量类型默认值,布尔值默认是false,除了基本类型。其余默认值都是null(类里面方法外面,从属于对象)
- 类变量(static)
常量
-
关键词—final
-
常量字符大写
例:static final double PI = 3.14
运算符
int b = a++;//先赋值,再加1 |
Math类:
幂运算:Math.pow(3,2) //3*2=9
int a = 10; |
包机制
公司域名倒置作为包名
导入一个包下的所有类 —import com.kuang.base.*;
用户交互Scanner
Next()
public static void main(String[] args) { |
nextLine()
public static void main(String[] args) { |
- next()
- 一定要读取到有效字符才可以结束输入
- 对输入有效字符之前遇到的空白,next()方法会将其去掉
- 只有输入有效字符后才将其后面输入的空白作为结束符
- next()不能得到带有空格的字符串
- nextLine()
- 以Enter作为结束符,即返回输入回车之前所有的字符
- nextLine()可以获取空白
更多Scanner用法参见[Java 基础——Scanner 类](Java 基础——Scanner 类_java scanner-CSDN博客)
顺序结构
按照顺序一行一一行的执行
选择结构
- if单选择结构----if
- if双选择结构-----if…else
- if多选择结构-----if…else if…else if…else
- 嵌套if结构
- switch多选择结构
switch (变量或表达式的值) { |
循环结构
-
while循环
int i = 0;
while (i < 10) {
System.out.println(i);
i++;
} -
do while循环
int i = 0;
do {
System.out.println(i);
i++;
} while (i < 10); -
for循环
for (int i = 0; i < 10; i++) { |
-
增强for循环
int[] numbers = {1, 2, 3, 4, 5};
for (int number : numbers) {
System.out.println(number);
}break
break
关键字用于立即退出最内层的循环或者switch
语句
for (int i = 0; i < 10; i++) { |
continue
continue
关键字用于跳过当前循环的剩余部分
for (int i = 0; i < 10; i++) { |
标签(Labels):在 Java 中,标签可以与 break
和 continue
语句一起使用,用于跳出嵌套循环或者继续下一次迭代。
outer: // 标签 |
return
return
用于从函数中返回值并结束函数的执行。
def find_first_even(numbers): |
方法
修饰符 返回类型 方法名(参数类型 参数名) { |
方法重载
方法重载,指在同一个类中存在多个同名的方法,但它们的参数列表不同。参数列表的不同可以体现在参数的数量、类型或者参数的顺序上。
方法调用
-
静态方法(static)
类名.方法名
-
非静态方法
实例化这个类----new Student()
形参和实参
函数或方法定义时使用的参数称为形参,而在调用函数或方法时提供的参数称为实参。
值传递和引用传递
在 Java 中,所有的参数传递都是按值传递的。这意味着不管是一个原始数据类型还是一个对象,传递的都是一个副本。但是,对于对象来说,这个副本是一个指向对象内存地址的引用,而不是对象本身的副本。因此,尽管 Java 中的对象传递在技术上来说是按值传递的,但是因为传递的是引用,所以它的行为更像是按引用传递。
原始数据类型(Primitives):
Java 中的原始数据类型(如 int、float、double、byte、char 等)在传递给方法时是按值传递的。这意味着传递的是数据值的一个副本,而不是数据的内存地址。在方法内部对这个值的任何修改都不会影响到原始数据。
public class Main { |
对象(Objects):
Java 中的对象传递的是对象引用的副本。这意味着,如果在方法内部改变了引用指向的对象的状态,那么原始对象也会受到影响,因为引用指向的是同一个对象。但是,如果在方法内部改变了引用本身,使其指向一个新的对象,那么原始引用不会改变。
public class Main { |
可变参数
在Java中,可变参数通过在参数类型后面加上三个连续的点(…)来表示,这种参数被称为“变长参数”。
一个方法只能指定一个可变参数,它必须是方法的最后一个参数,任何普通的参数必须在它之前声明
public class VarArgsExample { |
递归
递归是一种编程技巧,它允许一个函数或方法调用自身。递归通常用于解决可以分解为多个相似或更小问题的问题,特别是那些具有自然递归结构的问题,如树遍历、图形搜索、排序算法(如快速排序和归并排序)以及一些数学计算(如计算阶乘、斐波那契数列等)。
public class Factorial { |
数组
- 数组是相同类型数据的有序集合
- 数组元素通过索引访问,数组索引从0开始
- 获取数组长度----arrays.length
- 数组长度是确定的,不可改变的,如果越界,报错ArrayIndexOutofBounds
int[] nums ;//int nums[]不推荐 |
内存分析
三种初始化
-
静态初始化
int[] numbers = {1, 2, 3, 4, 5}; // 静态初始化一个整型数组
String[] words = {"Hello", "World"}; // 静态初始化一个字符串数组 -
动态初始化
int[] dynamicNumbers = new int[size]; // 动态初始化一个整型数组
-
默认初始化
默认初始化发生在数组被声明但没有显式地赋予初始值时。在这种情况下,数组中的元素会被自动赋予该数据类型的默认值。
- 整型数组的默认值是0。
- 浮点型数组的默认值是0.0。
- char类型默认值是 ‘\u0000’
- 布尔型数组的默认值是false。
- 引用类型数组的默认值是null。
int[] defaults = new int[5]; // 默认初始化一个整型数组 |
数组的使用
遍历数组
// 使用for循环 |
多维数组
声明和初始化
// 声明一个二维整型数组 |
遍历多维数组
// 遍历二维数组 |
数组的长度
int rows = matrix.length; // 获取行数 |
Arrays类
排序
static void sort(int[] a)
: 对指定的整数数组进行排序。static void sort(Object[] a)
: 根据元素的自然顺序对指定对象数组进行排序。static <T> void sort(T[] a, Comparator<? super T> c)
: 根据指定比较器产生的顺序对指定对象数组进行排序。
搜索
—通过binarySearch方法对排好序的数组进行二分查找操作
static int binarySearch(int[] a, int key)
: 在指定的整数数组中搜索指定的值。static int binarySearch(Object[] a, Object key)
: 在指定的对象数组中搜索指定的值。static int binarySearch(Object[] a, Object key, Comparator<? super T> c)
: 根据指定比较器搜索指定对象数组中的指定值。
填充
static void fill(int[] a, int val)
: 将指定的整数值分配给指定整数数组的每个元素。static void fill(Object[] a, Object val)
: 将指定的对象引用分配给指定对象数组的每个元素。static void fill(int[] a, int fromIndex, int toIndex, int val) ;
指定开始和结束索引的填充
复制
static int[] copyOf(int[] original, int newLength)
: 复制指定的数组,截断或填充空位(如有必要),以使副本具有指定的长度。static <T> T[] copyOf(T[] original, int newLength)
: 复制指定的数组,截断或填充空位(如有必要),以使副本具有指定的长度。
比较
static boolean equals(int[] a, int[] a2)
: 如果两个指定的整数数组相等,则返回true
。static boolean equals(Object[] a, Object[] a2)
: 如果两个指定的对象数组相等,则返回true
。
转换为字符串
static String toString(int[] a)
: 返回一个表示指定数组内容的字符串。static String toString(Object[] a)
: 返回一个表示指定数组内容的字符串。
import java.util.Arrays; |
冒泡排序
算法步骤
- 比较相邻的元素。如果第一个比第二个大,就交换它们两个。
- 对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后已经排序好的元素。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
代码示例
import java.util.Arrays; |
稀疏数组
面向对象
面向对象编程的本质就是:以类的方式组织代码,以对象的组织(封装)数据
- 抽象
- 三大特性
- 封装
- 继承
- 多态
类与对象的关系:
- 类是对象的模板,对象是类的实例。
- 类定义了对象的结构和行为,而对象则实现了这些定义,并具有具体的数据。
构造器
构造器的特点:
- 构造器的名称必须与类名完全相同。
- 构造器没有返回类型,也不可以使用
void
关键字。 - 构造器在对象创建时自动调用,且只调用一次。
- 构造器可以重载,即可以有多个构造器,它们之间在参数数量或类型上有所不同。
public class Person { |
注意:一旦定义有参构造,无参构造必须显示定义
封装
-----高内聚低耦合
属性私有,方法公有
public class Person { |
继承
快捷键:Ctrl +H---------查看继承关系
在Java在所有类,都默认直接或间接的继承Object类
- 继承本质是对某一批类的抽象
- extends关键词,子类对父类的扩展
- Java中只有单继承,没有多继承
- 子类和父类之间,具有“is a”关系
super详解
this
用于引用当前对象,可以用来访问当前对象的属性和方法,也可以用来调用当前类的构造器。super
用于引用父类,可以用来访问父类的属性和方法,也可以用来调用父类的构造器。
调用父类构造器,super()必须要在第一行
相关详细内容参见
方法重写
方法重写是面向对象多态性的一个重要方面,它允许子类以特定的方式实现父类的行为,从而提供更丰富的功能和灵活性。
方法重写的条件:
- 继承关系:子类必须继承自父类。
- 方法签名:子类中的方法必须与父类中被重写的方法具有相同的方法名和参数列表(方法签名)。
- 返回类型:子类中的方法的返回类型必须与父类中被重写的方法的返回类型相同,或者是被重写方法返回类型的子类型(covariant return type)。
- 访问权限:子类中方法的访问权限不能比父类中被重写的方法的访问权限更低(例如,如果父类方法是
public
,子类方法不能是private
)。 - 静态与非静态:子类重写的方法必须与父类中被重写的方法具有相同的静态或非静态属性(不能将父类的实例方法重写为静态方法,反之亦然)。
静态方法-----与方法重写无关
class Animal { |
非静态方法------重写
class Animal { |
多态
示例1:
Dog myDog = new Dog(); |
- 子类能调用的方法都是自己的或者继承父类的
- 父类可以指向子类类型,但不能调用子类的独有方法;调用子类独有方法,可将父类型强转为子类型
示例2:
class Animal { |
myAnimal1 和 myAnimal2 都是 Animal 类型的引用,但它们分别指向了一个 Dog 对象和一个 Cat 对象。当调用 makeSound() 方法时,会根据实际对象的类型来执行相应的方法,这就是运行时多态。
instanceof和类型转化
instanceof
instanceof
是一个关键字,用于检查一个对象是否是一个特定类的实例
class Animal {} |
对象的类型转化
- 向上转型(Upcasting):向上转型是指将一个子类对象转换为其父类类型的过程。由于子类对象可以被看作是父类对象,所以向上转型是安全的,不会导致数据丢失或溢出。在向上转型中,父类引用指向了子类对象。
class Animal {} |
- 向下转型(Downcasting):向下转型是指将一个父类类型的对象转换为其子类类型的过程。向下转型需要显式地进行,使用强制类型转换操作符。由于父类对象并不具备子类特有的属性和行为,所以在向下转型时需要确保对象实际上是子类对象,否则可能会导致
ClassCastException
异常。
class Animal {} |
需要注意的是,在进行向下转型时,必须确保对象的实际类型是目标类型,否则会抛出ClassCastException
异常。为了避免此类异常,可以使用instanceof
运算符来检查对象的类型,再进行向下转型。
if (animal instanceof Dog) { |
static详解
static
是一个关键字,用于声明类级别的成员,也就是说,被static
修饰的成员属于类本身,而不是类的实例。
- 静态变量(类变量):使用
static
修饰的变量称为静态变量,也叫类变量。所有该类的对象共享相同的静态变量,它们的值在所有实例之间是共享的。静态变量在类加载时初始化,并且只会被初始化一次。静态变量可以通过类名直接访问,无需创建类的实例。
class Student { |
- 静态方法:使用
static
修饰的方法称为静态方法。静态方法可以直接通过类名调用,无需创建类的实例。静态方法只能访问静态变量和调用静态方法,无法访问非静态的实例变量和实例方法。
class MyClass { |
- 静态代码块:静态代码块在类被加载时执行,仅执行一次。它常用于静态变量的初始化或执行一些静态操作。
class MyClass { |
- 静态内部类:使用
static
关键字修饰的内部类称为静态内部类。静态内部类与外部类的实例无关,可以直接通过外部类的类名访问,无需先创建外部类的实例。
class OuterClass { |
抽象类
关键词:extends
- 抽象方法只有方法签名(方法名、返回类型、参数列表),没有具体实现(没有方法体)。
- 抽象方法必须在抽象类中声明。
- 不能new 这个抽象类,只能靠子类去实现它:约束!
- 抽象类可以写非抽象方法,构造器,静态成员
- 子类继承抽象类时,必须实现所有的抽象方法,除非子类也是抽象类。
abstract class Animal {//抽象类 |
接口
定义:接口(Interface)是一种定义行为的方式,它是完全抽象的,用来声明方法但不包含方法的实现。 接口使用interface
关键字来定义,其中的方法默认都是公共的(public)和抽象的(abstract),即使你不明确写出这些修饰符。
- 普通类:只有具体实现
- 抽象类:具体实现和规范(抽象方法)都有
- 接口:只有规范!自己无法写方法
public interface MyInterface { |
public class MyClass implements MyInterface { |
多重继承: Java不支持类的多重继承,但可以通过实现多个接口来达到类似的效果,从而实现多重继承的功能。
public class MyClass implements A ,B{ |
接口与抽象类的区别:
- 抽象类可以有构造方法,可以有实例变量,而接口不能有构造方法。
- 类只能单继承(extends)一个抽象类,但可以实现多个接口(implements)。
- 抽象类可以有抽象方法和非抽象方法,接口中的方法默认都是抽象的(除非是默认方法或静态方法)。
内部类
-
成员内部类: 成员内部类是定义在另一个类内部的类。它具有对外部类成员的完全访问权限,并且可以访问外部类的所有成员,包括私有成员。
class OuterClass {
private int outerVar;
class InnerClass {
void display() {
System.out.println("Outer variable: " + outerVar);
}
}
}
// 实例化成员内部类
OuterClass outerObj = new OuterClass();
OuterClass.InnerClass innerObj = outerObj.new InnerClass(); -
静态内部类: 静态内部类是定义在另一个类内部的静态类。它不依赖于外部类的实例,并且不能直接访问外部类的非静态成员。
class OuterClass {
static class StaticInnerClass {
void display() {
System.out.println("Static Inner Class");
}
}
}
// 实例化静态内部类
OuterClass.StaticInnerClass staticInnerObj = new OuterClass.StaticInnerClass(); -
局部内部类: 局部内部类是定义在方法或作用域内部的类。它只在所定义的方法或作用域内可见,并且不能使用访问修饰符 public、protected 或 private。
class OuterClass {
void someMethod() {
class LocalInnerClass {
void display() {
System.out.println("Local Inner Class");
}
}
// 实例化局部内部类
LocalInnerClass localInnerObj = new LocalInnerClass();
localInnerObj.display();
}
} -
匿名内部类: 匿名内部类是没有显式名称的内部类,通常用于创建一个临时的类实例,通常是接口或抽象类的实现。
interface MyInterface {
void display();
}
class OuterClass {
void someMethod() {
// 匿名内部类实现 MyInterface 接口
MyInterface anonymousInnerObj = new MyInterface() {
public void display() {
System.out.println("Anonymous Inner Class");
}
};
anonymousInnerObj.display();
}
}
异常
捕获和抛出异常
关键词:try, catch,finally,throw,throws
try-catch-finally
用于捕获和处理异常,并在不管是否发生异常的情况下执行清理操作。-----------快捷键:Ctrl +Alt +T
基本语法
try { |
示例:
public class TryCatchFinallyExample { |
throw
用于显式抛出一个异常。当你在代码中遇到某种错误情况,希望程序停止当前执行流程并传递错误信息时,就可以使用 throw
语句。
基本语法
Java
1throw new ExceptionType(message); |
-
ExceptionType
是你想要抛出的异常类型的名称,它必须是Throwable
类或其子类的实例。 -
message
是一个可选的字符串参数,用于描述发生异常的具体情况,可不写。
示例:
public class Main { |
throws
用于声明方法可能会抛出的一个或多个异常类型。它告知调用者,调用这个方法时可能会遇到某些异常情况,需要调用者负责处理这些潜在的异常。
基本语法
在方法签名后使用 throws
关键字,后跟一个或多个异常类名,这些类必须是 Throwable
的子类:
public returnType methodName() throws ExceptionType1, ExceptionType2 { |
示例
Java
public void readFile(String fileName) throws FileNotFoundException, IOException { |
自定义异常
自定义异常是指根据特定需求创建的异常类,这些类通常继承自现有的异常类,如 Exception
类或其子类
1. 定义自定义异常类
首先,你需要定义一个新的类,让它继承自现有的异常类。最常见的是直接继承 Exception
类或它的子类,比如 RuntimeException
。通常,自定义异常类至少包含一个无参构造函数和一个带有详细错误信息的构造函数
public class MyCustomException extends Exception { |
2. 抛出自定义异常
在需要的地方,你可以像抛出标准异常一样,使用 throw
关键字抛出自定义异常。
public void someMethod(String input) throws MyCustomException { |
3. 捕获和处理自定义异常
调用可能抛出自定义异常的方法时,你需要使用 try-catch
语句块来捕获并处理这个异常。
public static void main(String[] args) { |