(超级详细版)Java基础:Java常用变量详解
在Java编程中,变量是存储数据的基本单元。了解和正确使用变量是掌握Java编程的关键一步。本文将详细介绍Java中的常用变量类型,包括基本数据类型和引用数据类型,并探讨它们的使用场景和注意事项。
一、基本数据类型(Primitive Data Types)
Java提供了八种基本数据类型,这些类型是Java中最基础的变量类型,用于存储简单的数据。
1. 整数类型(Integer Types)
(1)byte
- 定义:
byte
是 Java 中最小的整数类型,占 1 个字节(8 位),取值范围是 -128 到 127。 - 使用场景:适用于需要节省内存且数据范围较小的场景,如处理二进制数据或文件流。
byte b = 100;
(2)short
- 定义:
short
占 2 个字节(16 位),取值范围是 -32,768 到 32,767。 - 使用场景:适用于中等大小的整数,但较少使用。
short s = 10000;
(3)int
- 定义:
int
占 4 个字节(32 位),取值范围是 -2^31 到 2^31-1。 - 使用场景:最常用的整数类型,适用于大多数整数场景。
int i = 100000;
(4)long
- 定义:
long
占 8 个字节(64 位),取值范围是 -2^63 到 2^63-1。 - 使用场景:适用于需要更大取值范围的整数,如时间戳、大数值计算等。
- 注意事项:
long
类型的字面值需要在数字后面加上L
或l
以标识。
long l = 100000L;
2. 浮点类型(Floating-Point Types)
(1)float
- 定义:
float
占 4 个字节(32 位),用于表示单精度浮点数。 - 使用场景:适用于对精度要求不高的浮点数计算。
- 注意事项:
float
类型的字面值需要在数字后面加上F
或f
以标识。
float f = 3.14F;
(2)double
- 定义:
double
占 8 个字节(64 位),用于表示双精度浮点数。 - 使用场景:最常用的浮点类型,适用于大多数科学计算和工程计算。
double d = 3.14159;
3. 字符类型(Character Type)
(1)char
- 定义:
char
占 2 个字节(16 位),用于表示单个字符,使用单引号'
括起来。 - 使用场景:适用于表示字符常量,如字母、数字字符、符号等。
char c = 'A';
4. 布尔类型(Boolean Type)
(1)boolean
- 定义:
boolean
类型只占 1 位,用于表示逻辑值,只能取true
或false
。 - 使用场景:适用于条件判断和逻辑控制。
boolean flag = true;
二、引用数据类型(Reference Data Types)
引用数据类型是指对象类型的变量,它们是通过引用(内存地址)来访问对象的。
1. 类(Class)
(1)定义
- 定义:类是 Java 中最常见的引用类型,定义了对象的属性和方法。
- 使用场景:适用于复杂的对象模型和面向对象编程。
class Book {
String title;
String author;
}
Book book = new Book();
2. 数组(Array)
(1)定义
- 定义:数组是一种用于存储固定大小、同类型元素的数据结构。数组一旦创建,其大小不可改变。
- 使用场景:适用于存储和处理一组相同类型的数据,如学生成绩、一组数字等。
(2)声明和初始化
// 一维数组
int[] numbers = new int[5]; // 声明一个长度为5的int类型数组
numbers[0] = 1; // 赋值
// 也可以直接初始化
int[] numbers = {1, 2, 3, 4, 5}; // 声明并初始化
// 多维数组
int[][] matrix = new int[3][3]; // 声明一个3x3的二维数组
matrix[0][0] = 1; // 赋值
// 直接初始化二维数组
int[][] matrix = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
(3)注意事项
- 固定大小:数组的大小在创建时确定,之后不能改变。
- 索引从0开始:数组的索引从0开始,到length-1结束。
- 多维数组:可以创建多维数组,如二维数组(矩阵)、三维数组等。
3. 字符串(String)
(1)定义
- 定义:
String
是一种特殊的引用类型,用于表示字符串。虽然它是引用类型,但它的值是不可变的(immutable)。 - 使用场景:适用于处理文本数据,如句子、单词、文件路径等。
(2)声明和初始化
String str = "Hello, World!"; // 声明并初始化一个字符串
(3)常用方法
length()
:返回字符串的长度。
int length = str.length(); // 返回13
charAt(int index)
:返回指定索引处的字符。
char ch = str.charAt(0); // 返回 'H'
substring(int beginIndex, int endIndex)
:返回子字符串。
String subStr = str.substring(0, 5); // 返回 "Hello"
equals(Object anotherObject)
:比较字符串内容是否相等。
boolean isEqual = str.equals("Hello, World!"); // 返回 true
toUpperCase()
和toLowerCase()
:将字符串转换为大写或小写。
String upperStr = str.toUpperCase(); // 返回 "HELLO, WORLD!"
String lowerStr = str.toLowerCase(); // 返回 "hello, world!"
(4)注意事项
- 不可变性:字符串一旦创建,其内容不可改变。任何修改操作都会创建一个新的字符串对象。
- 字符串池:Java 对字符串进行了优化,使用字符串池(String Pool)来存储字符串常量,以提高性能。
4. 枚举(Enum)
(1)定义
- 定义:
enum
是一种特殊的类类型,用于表示一组固定的常量。 - 使用场景:适用于表示一组有限的选项或状态,如星期几、颜色等。
(2)声明和使用
enum Day {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}
Day day = Day.MONDAY; // 使用枚举
(3)常用方法
values()
:返回枚举常量的数组。
Day[] days = Day.values(); // 返回所有枚举常量
valueOf(String name)
:根据名称获取枚举常量。
Day day = Day.valueOf("MONDAY"); // 返回 Day.MONDAY
(4)注意事项
(2)声明和使用
interface Animal {
void eat();
void sleep();
}
class Dog implements Animal {
@Override
public void eat() {
System.out.println("Dog is eating");
}
@Override
public void sleep() {
System.out.println("Dog is sleeping");
}
}
public class InterfaceExample {
public static void main(String[] args) {
Animal myDog = new Dog();
myDog.eat(); // 输出: Dog is eating
myDog.sleep(); // 输出: Dog is sleeping
}
}
(3)默认方法和静态方法
interface Animal {
void eat();
void sleep();
// 默认方法
default void play() {
System.out.println("Animal is playing");
}
}
interface Animal {
static void sound() {
System.out.println("Some animal sound");
}
}
public class InterfaceExample {
public static void main(String[] args) {
Animal.sound(); // 输出: Some animal sound
}
}
(4)注意事项
6. 泛型(Generics)
(1)定义
(2)泛型类
class Box<T> {
private T item;
public void set(T item) {
this.item = item;
}
public T get() {
return this.item;
}
}
public class GenericsExample {
public static void main(String[] args) {
Box<String> stringBox = new Box<>();
stringBox.set("Hello, World!");
System.out.println(stringBox.get()); // 输出: Hello, World!
Box<Integer> intBox = new Box<>();
intBox.set(123);
System.out.println(intBox.get()); // 输出: 123
}
}
- 类型安全:枚举类型是类型安全的,比使用整数常量更安全和易读。
- 枚举方法:枚举本质上是一个特殊的类,因此可以为其定义构造方法、成员变量和方法。
-
enum Day { MONDAY("Weekday"), TUESDAY("Weekday"), WEDNESDAY("Weekday"), THURSDAY("Weekday"), FRIDAY("Weekday"), SATURDAY("Weekend"), SUNDAY("Weekend"); private String type; // 构造方法 Day(String type) { this.type = type; } // 获取类型 public String getType() { return this.type; } } public class EnumExample { public static void main(String[] args) { Day day = Day.MONDAY; System.out.println(day + " is a " + day.getType()); // 输出: MONDAY is a Weekday } }
switch
语句:枚举可以与switch
语句一起使用,以实现更清晰的逻辑控制。-
Day day = Day.MONDAY; switch (day) { case MONDAY: System.out.println("Start of the work week"); break; case FRIDAY: System.out.println("End of the work week"); break; default: System.out.println("Weekend"); }
5. 接口(Interface)
(1)定义
- 定义:接口是一种引用类型,类似于类,但只包含常量和抽象方法的定义。
- 使用场景:适用于定义对象的行为规范,使不同的类可以遵循相同的接口实现相似的功能。
- 默认方法:从 Java 8 开始,接口可以包含默认方法,这些方法有默认实现。
- 静态方法:接口也可以包含静态方法,这些方法属于接口本身。
- 多继承:一个类可以实现多个接口,这在某种程度上实现了多继承。
- 抽象契约:接口主要用于定义对象的行为契约,不涉及具体的实现细节。
- 定义:泛型是 Java 提供的一种机制,允许在类、接口和方法中使用类型参数,从而实现代码的复用性和类型安全性。
- 使用场景:适用于需要处理不同类型的数据结构和算法,如集合、映射等。
3)泛型方法
- 定义:泛型方法是可以在方法级别定义类型参数的方法,独立于类的类型参数。
class GenericsMethodExample {
// 泛型方法
public static <T> void printArray(T[] array) {
for (T item : array) {
System.out.println(item);
}
}
public static void main(String[] args) {
Integer[] intArray = {1, 2, 3, 4, 5};
String[] stringArray = {"A", "B", "C"};
printArray(intArray); // 输出: 1 2 3 4 5
printArray(stringArray); // 输出: A B C
}
}
(4)泛型接口
- 定义:接口也可以使用泛型,从而使实现类根据需要指定类型参数。
interface GenericInterface<T> {
T getValue();
}
class GenericInterfaceImpl<T> implements GenericInterface<T> {
private T value;
public GenericInterfaceImpl(T value) {
this.value = value;
}
@Override
public T getValue() {
return this.value;
}
}
public class InterfaceGenericsExample {
public static void main(String[] args) {
GenericInterface<String> stringInterface = new GenericInterfaceImpl<>("Hello");
System.out.println(stringInterface.getValue()); // 输出: Hello
GenericInterface<Integer> intInterface = new GenericInterfaceImpl<>(123);
System.out.println(intInterface.getValue()); // 输出: 123
}
}
(5)注意事项
- 类型擦除:Java 中的泛型是通过类型擦除(Type Erasure)实现的,这意味着在运行时,泛型类型信息会被擦除,以保证与非泛型代码的兼容性。
- 通配符:可以使用
?
作为通配符,表示未知类型,常用于泛型方法和泛型类的参数。
// 上界通配符
public static void printNumbers(List<? extends Number> list) {
for (Number number : list) {
System.out.println(number);
}
}
// 下界通配符
public static void addNumbers(List<? super Integer> list) {
list.add(100);
}
7. 集合框架(Collections Framework)
(1)定义
- 定义:Java 集合框架(Collections Framework)是一组类和接口,用于存储和操作一组对象。集合框架提供了多种数据结构,如列表、集合、映射等。
- 使用场景:适用于需要动态存储和管理一组对象的场景。
(2)常用集合接口和类
List
:有序集合,允许存储重复元素。ArrayList
:基于数组的实现,支持快速随机访问。
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
System.out.println(list.get(0)); // 输出: A
LinkedList
:基于链表的实现,支持快速的插入和删除操作。
List<String> list = new LinkedList<>();
list.add("A");
list.add("B");
list.add("C");
System.out.println(list.get(1)); // 输出: B
Set
:无序集合,不允许存储重复元素。HashSet
:基于哈希表的实现,提供常数时间的添加、删除和查找操作。
Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
set.add("C");
System.out.println(set.contains("A")); // 输出: true
TreeSet
:基于红黑树的实现,元素按自然顺序排序或根据自定义比较器排序。
Set<String> set = new TreeSet<>();
set.add("B");
set.add("A");
set.add("C");
// 输出: [A, B, C] (按自然顺序排序)
System.out.println(set);
Map
:存储键值对,键必须唯一。HashMap
:基于哈希表的实现,提供常数时间的添加、删除和查找操作。
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
System.out.println(map.get("B")); // 输出: 2
TreeMap
:基于红黑树的实现,键按自然顺序排序或根据自定义比较器排序。
Map<String, Integer> map = new TreeMap<>();
map.put("B", 2);
map.put("A", 1);
map.put("C", 3);
// 输出: {A=1, B=2, C=3} (按键的自然顺序排序)
System.out.println(map);
(3)常用方法
-
List
常用方法add(E element)
:将元素添加到列表末尾。get(int index)
:返回指定索引处的元素。remove(int index)
:移除指定索引处的元素。size()
:返回列表中的元素数量。contains(Object o)
:判断列表是否包含指定元素。
-
Set
常用方法add(E element)
:将元素添加到集合中。contains(Object o)
:判断集合是否包含指定元素。size()
:返回集合中的元素数量。remove(Object o)
:移除指定元素。
-
Map
常用方法put(K key, V value)
:将键值对放入映射中。get(Object key)
:返回指定键对应的值。containsKey(Object key)
:判断映射是否包含指定键。keySet()
:返回映射中所有键的集合。values()
:返回映射中所有值的集合。size()
:返回映射中的键值对数量。
(4)注意事项
- 线程安全:Java 集合框架中的大多数类都是非线程安全的。如果需要在多线程环境下使用,可以考虑使用同步包装器或并发包中的类,如
Collections.synchronizedXXX
或ConcurrentHashMap
。 - 性能:不同集合类的性能特性不同,选择时需根据具体场景权衡。例如,
ArrayList
适合随机访问,而LinkedList
适合频繁插入和删除操作。 - 不可变集合:Java 9 引入了不可变集合,可以通过
List.of()
,Set.of()
,Map.of()
等方法创建不可变集合。
List<String> immutableList = List.of("A", "B", "C");
Set<Integer> immutableSet = Set.of(1, 2, 3);
Map<String, String> immutableMap = Map.of("key1", "value1", "key2", "value2");
8. 异常处理(Exception Handling)
(1)定义
throw new MyCustomException("Something went wrong with the operation on object X");
try (FileReader reader = new FileReader("file.txt")) {
// 使用 FileReader 读取文件
} catch (IOException e) {
// 处理异常
}
(6)常见的 Java 异常
9. Java 并发(Concurrency)
(1)定义
(2)创建线程
class MyThread extends Thread {
@Override
public void run() {
System.out.println("Thread is running.");
}
}
public class ThreadExample {
public static void main(String[] args) {
MyThread thread = new MyThread();
thread.start(); // 启动新线程
}
}
- 定义:异常处理是 Java 提供的一种机制,用于处理程序运行时的错误,以保证程序的健壮性。
- 使用场景:适用于捕获和处理运行时错误,如文件未找到、网络连接失败等。
-
(2)异常分类
- 受检异常(Checked Exception):这些异常在编译时被检查,必须通过
try-catch
块捕获或在方法签名中通过throws
声明抛出。常见的受检异常包括IOException
,SQLException
等。 -
import java.io.FileReader; import java.io.IOException; public class CheckedExceptionExample { public static void main(String[] args) { try { FileReader reader = new FileReader("file.txt"); // 其他操作 } catch (IOException e) { System.out.println("An error occurred: " + e.getMessage()); } } }
- 非受检异常(Unchecked Exception):这些异常是运行时异常(
RuntimeException
),在编译时不会强制要求处理。常见的非受检异常包括NullPointerException
,ArrayIndexOutOfBoundsException
,ArithmeticException
等。 -
public class UncheckedExceptionExample { public static void main(String[] args) { try { String str = null; System.out.println(str.length()); // 抛出 NullPointerException } catch (NullPointerException e) { System.out.println("A null pointer exception occurred."); } } }
- 错误(Error):错误通常表示严重的系统问题,如
OutOfMemoryError
,StackOverflowError
等,一般不建议捕获和处理。 -
(3)异常处理机制
try-catch
块:用于捕获和处理异常。-
try { // 可能抛出异常的代码 } catch (ExceptionType e) { // 处理异常 } finally { // 可选的,无论是否发生异常都会执行的代码 }
try-with-resources
:Java 7 引入了try-with-resources
声明,可以自动关闭实现了AutoCloseable
接口的资源(如文件、流等),从而避免手动关闭资源。-
import java.io.FileReader; import java.io.IOException; public class TryWithResourcesExample { public static void main(String[] args) { try (FileReader reader = new FileReader("file.txt")) { // 使用 FileReader 读取文件 } catch (IOException e) { System.out.println("An I/O error occurred: " + e.getMessage()); } } }
throw
和throws
:throw
:用于显式抛出异常。
-
public class ThrowExample { public static void checkAge(int age) { if (age < 18) { throw new ArithmeticException("Access denied - You must be at least 18 years old."); } else { System.out.println("Access granted."); } } public static void main(String[] args) { checkAge(15); // 抛出 ArithmeticException } }
throws
:用于方法签名中声明该方法可能抛出的受检异常。-
import java.io.IOException; public class ThrowsExample { public void readFile(String filePath) throws IOException { // 读取文件的代码可能抛出 IOException throw new IOException("File not found."); } public static void main(String[] args) { try { ThrowsExample example = new ThrowsExample(); example.readFile("file.txt"); } catch (IOException e) { System.out.println("An error occurred: " + e.getMessage()); } } }
(4)自定义异常
- 定义:可以创建自定义异常类,通过继承
Exception
类或其子类(如RuntimeException
)来实现。 -
// 自定义异常类 class InvalidAgeException extends Exception { public InvalidAgeException(String message) { super(message); } } public class CustomExceptionExample { // 方法可能抛出自定义异常 public static void checkAge(int age) throws InvalidAgeException { if (age < 18) { throw new InvalidAgeException("You must be at least 18 years old."); } else { System.out.println("Access granted."); } } public static void main(String[] args) { try { checkAge(15); // 传入小于18的年龄,抛出异常 } catch (InvalidAgeException e) { System.out.println("Caught an exception: " + e.getMessage()); } } }
在这个例子中,我们定义了一个自定义异常
InvalidAgeException
,并在checkAge
方法中根据条件抛出该异常。在main
方法中通过try-catch
块捕获并处理这个异常。(5)异常处理的最佳实践
- 尽量具体:捕获异常时,尽量指定具体的异常类型,而不是直接捕获
Exception
。这样可以更好地处理不同类型的异常。 -
try { // 可能抛出多种异常的代码 } catch (NullPointerException e) { // 处理空指针异常 } catch (IOException e) { // 处理IO异常 }
- 不要忽略异常:即使在
catch
块中不做太多处理,至少应该记录异常信息。 -
try { // 可能抛出异常的代码 } catch (Exception e) { e.printStackTrace(); // 至少记录异常日志 }
-
避免过度使用受检异常:过度使用受检异常可能会导致代码冗余,建议只在必要时使用。
-
使用详细的异常信息:在抛出自定义异常或任何异常时,提供详细的信息可以帮助调试和问题定位。
- 清理资源:使用
try-with-resources
或在finally
块中清理资源,确保即使在发生异常时也能正确释放资源。 - 不要使用异常来控制流程:异常应该用于处理错误情况,而不是用于正常的控制流。例如,不要使用异常来代替简单的
if-else
判断。 NullPointerException
:试图在null
对象上调用方法或访问字段时抛出。ArrayIndexOutOfBoundsException
:数组访问超出边界时抛出。ArithmeticException
:算术运算异常,如除以零时抛出。ClassNotFoundException
:当 JVM 找不到指定的类时抛出。IOException
:输入输出操作失败时抛出。SQLException
:与数据库操作相关的异常。IllegalArgumentException
:方法接收到非法参数时抛出。- 定义:Java 并发是指在 Java 程序中同时执行多个任务的能力。Java 提供了丰富的并发 API,以支持多线程编程。
- 使用场景:适用于需要同时处理多个任务的场景,如服务器处理多个客户端请求、并行计算等。
- 继承
Thread
类:通过继承Thread
类并重写run
方法来创建线程。
- 实现
Runnable
接口:通过实现Runnable
接口并传递给Thread
类来创建线程,这种方式比继承Thread
更灵活,因为 Java 不支持多继承。
class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println("Runnable is running.");
}
}
public class RunnableExample {
public static void main(String[] args) {
MyRunnable runnable = new MyRunnable();
Thread thread = new Thread(runnable);
thread.start(); // 启动新线程
}
}
- Lambda 表达式(Java 8+):如果使用的是 Java 8 及以上版本,可以通过 Lambda 表达式简化
Runnable
的实现。
public class LambdaThreadExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("Lambda Runnable is running.");
});
thread.start(); // 启动新线程
}
}
(3)线程的生命周期
线程的生命周期包括以下几种状态:
- New:线程被创建但尚未启动。
- Runnable:线程正在 Java 虚拟机中执行。
- Blocked:线程等待监视器锁以进入或重新进入同步块/方法。
- Waiting:线程等待另一个线程执行特定操作。
- Timed Waiting:线程等待另一个线程执行特定操作达到指定时间。
- Terminated:线程执行完毕或因异常退出。
可以通过 Thread.getState()
方法获取线程的状态。
public class ThreadStateExample {
public static void main(String[] args) {
Thread thread = new Thread(() -> {
try {
Thread.sleep(2000); // 模拟一些工作
} catch (InterruptedException e) {
e.printStackTrace();
}
});
System.out.println("Before start: " + thread.getState()); // 输出: NEW
thread.start();
System.out.println("After start: " + thread.getState()); // 输出: RUNNABLE
try {
Thread.sleep(1000); // 主线程休眠1秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("After 1 second: " + thread.getState()); // 可能输出: TIMED_WAITING 或 RUNNABLE
try {
thread.join(); // 主线程等待子线程结束
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("After completion: " + thread.getState()); // 输出: TERMINATED
}
}
(4)线程同步
synchronized
关键字:用于解决多个线程访问共享资源时的竞态条件问题。
public class SynchronizedExample {
private int count = 0;
// synchronized 方法
public synchronized void increment() {
count++;
}
public int getCount() {
return count;
}
public static void main(String[] args) {
SynchronizedExample example = new SynchronizedExample();
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
example.increment();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
example.increment();
}
});
t1.start();
t2.start();
try {
t1.join();
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + example.getCount()); // 输出: 20000
}
}
熟悉Java常用变量类型对于Java开发者来说至关重要。这些变量类型包括基本数据类型(如int、float、boolean)和引用类型(如String、数组)。掌握这些类型不仅有助于编写更精确、更高效的代码,还能提高程序的可靠性和可维护性
希望你喜欢这篇文章!请点关注和收藏吧。你的关注和收藏会是我努力更新的动力,祝关注和收藏的帅哥美女们今年都能暴富。如果有更多问题,欢迎随时提问