文章目录
一. Nested Classes嵌套类
嵌套类(Nested Class),也称为内部类,是在一个类内部定义的类。在 Java 中,你可以在一个类的内部定义另一个类,这个被定义的类就成为嵌套类。嵌套类可以有不同的类型,包括静态嵌套类、成员内部类、局部内部类和匿名内部类。
1. 静态嵌套类(Static Nested Class)
- 静态嵌套类是定义在外部类内部的静态类。
- 它可以通过外部类的名称直接访问,无需创建外部类的实例。
- 静态嵌套类不能访问外部类的非静态成员。
public class OuterClass {
static class StaticNestedClass {
// 静态嵌套类的代码
}
}
静态嵌套类可以直接通过外部类的名称来访问,无需创建外部类的实例。
OuterClass.StaticNestedClass nestedObj = new OuterClass.StaticNestedClass();
2. 成员内部类(Member Inner Class)
- 成员内部类是定义在外部类内部的非静态类。
- 它可以访问外部类的实例变量和方法,甚至可以引用外部类的 this。
- 成员内部类必须通过外部类的实例来访问。
public class OuterClass {
class MemberInnerClass {
// 成员内部类的代码
}
}
成员内部类需要通过外部类的实例来访问。
OuterClass outerObj = new OuterClass();
OuterClass.MemberInnerClass innerObj = outerObj.new MemberInnerClass();
3. 局部内部类(Local Inner Class)
- 局部内部类是定义在方法内部的类。
- 它只在包含它的方法中可见,外部类无法访问。
- 局部内部类可以访问外部类的实例变量和方法,但这些变量和方法必须是 final 或等效的。
public class OuterClass {
public void someMethod() {
class LocalInnerClass {
// 局部内部类的代码
}
}
}
局部内部类只在包含它的方法中可见,无法在方法外访问。
public class OuterClass {
public void someMethod() {
class LocalInnerClass {
// 局部内部类的代码
}
LocalInnerClass localObj = new LocalInnerClass();
}
}
4. 匿名内部类(Anonymous Inner Class)
- 匿名内部类是没有命名的内部类,通常用于创建临时的类实例。
- 它可以用来实现接口或继承类,并在实例化的同时提供具体的实现。
public class OuterClass {
public void someMethod() {
InterfaceName obj = new InterfaceName() {
// 匿名内部类的实现
};
}
}
匿名内部类通常用于实现接口或继承类,并在实例化时提供实现。
InterfaceName obj = new InterfaceName() {
// 匿名内部类的实现
};
二.functional interfaces
函数式接口(Functional Interface)是一种特殊的接口,它只包含一个抽象方法。函数式接口是 Java 8 引入的概念,它支持函数式编程,使得你可以将函数作为参数传递、在方法中返回函数,以及在 Lambda 表达式中使用。
1. 函数式接口的主要特点
- 函数式接口只包含一个抽象方法,但可以包含默认方法和静态方法。
- 函数式接口的抽象方法用于定义函数签名,可以在 Lambda 表达式中实现。
- 函数式接口通常用 @FunctionalInterface 注解来标记,这有助于编译器检查是否符合函数式接口的规则。
@FunctionalInterface
interface MyFunctionalInterface {
void myMethod();
}
//上面的示例定义了一个函数式接口 MyFunctionalInterface,它只包含一个抽象方法 myMethod。
//可以在该接口中定义其他默认方法和静态方法,但只能有一个抽象方法。
2. Lambda 表达式和函数式接口
函数式接口的主要用途之一是与 Lambda 表达式一起使用。Lambda 表达式允许你实现函数式接口的抽象方法,而无需创建匿名内部类。
MyFunctionalInterface functionalObj = () -> {
System.out.println("Lambda expression implementation");
};
3. 预定义的函数式接口
Java 提供了许多预定义的函数式接口,它们可用于不同的场景,例如函数参数传递、集合操作等。一些常见的预定义函数式接口包括 Consumer、Supplier、Predicate、Function 等。这些接口在 java.util.function 包中定义。
// 使用预定义的函数式接口 Consumer
Consumer<String> printString = s -> System.out.println(s);
printString.accept("Hello, World!");
4. 函数式编程的好处
函数式接口和 Lambda 表达式使得函数式编程成为可能。它们使代码更加简洁、易读,并支持并行编程。这对于处理集合、流、并行计算等任务非常有用。
三. Lambda Expressions
Lambda 表达式允许你以更紧凑的方式定义匿名内部类,通常用于实现函数式接口。
oracle_lambda
1. Lambda 表达式的基本语法
- parameters:这是 Lambda 表达式的参数列表,类似于方法的参数列表。可以为空括号 (),包含一个参数,或包含多个参数。
- ->:箭头符号,用于分隔参数列表和 Lambda 表达式的主体。
- expression:这是 Lambda 表达式的主体,包含了执行的代码块。
(parameters) -> expression
- 在 Lambda 表达式中,参数类型可以显式声明,也可以根据上下文自动推断。
(1)显式声明参数类型
Predicate<String> nonEmpty = (String x) -> x.length() > 0;
如果 Lambda 表达式是局部变量,编译器无法推断参数类型,因此需要显式声明
var lambda = (int x) -> x + 1;
(2)不显式声明参数类型,编译器会根据上下文推断
Predicate<String> nonEmpty = x -> x.length() > 0;
2. Lambda 表达式的例子
(1)无参数
() -> System.out.println("Hello, Lambda!");
(2)一个参数
(int x) -> x * 2
(3)多个参数
(int x, int y) -> x + y
3. Lambda 表达式的应用
Lambda 表达式通常用于函数式接口的实现,这些接口只包含一个抽象方法。你可以通过 Lambda 表达式来创建函数式接口的实例,而不必显式编写匿名内部类。
// 使用 Lambda 表达式创建一个 Runnable 实例
Runnable runnable = () -> {
System.out.println("Running from a Lambda expression.");
};
4. Lambda 表达式的优势
- 简洁性:Lambda 表达式可以使代码更加紧凑,减少样板代码。
- 可读性:Lambda 表达式通常更容易阅读,特别是在处理函数式编程的场景中。
- 函数式编程:Lambda 表达式促进了函数式编程风格,使 Java 更灵活和强大。
5. 注意事项
- Lambda 表达式必须与函数式接口一起使用,函数式接口是只包含一个抽象方法的接口。
- Lambda 表达式可以访问外部变量,但这些变量必须是隐式最终( effectively final),即它们不可被修改。
四. software complexity
1. Essential Complexity(本质复杂性)
本质复杂性是指与问题本身相关的复杂性,它是由于问题的本质属性和要解决的需求而产生的复杂性。这部分复杂性是不可避免的,因为它与问题领域的特性和要解决的问题的本质相关。本质复杂性可以被视为问题领域的固有复杂性,它不是软件开发过程中引入的。
2. Accidental Complexity(偶然复杂性)
偶然复杂性是指与软件开发过程和技术选择相关的复杂性,这部分复杂性是不必要的,是由于软件开发人员的决策、技术限制或其他非本质因素而引入的。偶然复杂性可以是由于糟糕的设计、低效的编程实践、不合理的技术选择或其他外部因素而引入的。
3. Not to be confused with computational complexity
五. The Number Classes
“The Number Classes” 是 Java 中一组用于表示数值类型的类的集合。这些类用于表示不同数据类型的数值,包括整数、浮点数和其他数值类型。
1. 常见的 Number 类及其主要子类
- java.lang.Number:这是 Number 类层次结构的根类。它定义了一些通用的方法,例如 intValue()、doubleValue()、floatValue() 和 longValue(),这些方法用于将数值转换为不同的基本数据类型。
- java.lang.Integer:这个类用于表示整数值,它是 Number 的子类。它包含了许多方法,用于整数值的操作和转换。
- java.lang.Long:类似于 Integer,但用于表示长整数值。
- java.lang.Float:这个类用于表示单精度浮点数,即 float 类型的值。它包含了方法来进行浮点数运算。
- java.lang.Double:类似于 Float,但用于表示双精度浮点数,即 double 类型的值。
- java.lang.Short:这个类用于表示短整数值,通常占用较少的内存空间。
- java.lang.Byte:类似于 Short,但用于表示字节值,通常用于处理二进制数据。
2. 和普通的 int、float、double 等基本数据类型之间的区别
“Number Classes” 和普通的 int、float、double 等基本数据类型之间的区别在于它们是 Java 中的类,而不是基本数据类型。这些类用于将数值封装成对象,提供了一些额外的功能和灵活性。
- “Number classes have a space overhead” 意味着数值类(如 Integer、Double、Float 等)在内存中占用的空间通常比相应的原始数据类型(如 int、double、float 等)更大。
- 这是因为数值类是对象,它们包含了额外的元数据和方法,用于处理数值。这些额外的数据和方法增加了对象的大小,因此会导致空间开销。
具体区别和优势包括:
(1)对象封装
Number 类及其子类是对象,而不是基本数据类型。这意味着它们可以包含额外的信息和方法。例如,Integer 类可以包含整数值以及许多用于整数操作的方法。
(2)多态性
通过使用 Number 类的引用,可以处理不同数值类型的对象。这使得编写通用的代码更容易,因为你可以在运行时决定使用哪种数值类型。
(3)方法和操作
Number 类及其子类提供了一系列方法,用于执行数值操作,如加法、减法、乘法和除法。这些方法可以用于处理数值,而不需要手动进行类型转换。
(4)封装
通过将数值封装在对象中,可以将它们传递给需要对象参数的方法,而不需要使用基本数据类型。
(5)Null 值
Number 类及其子类允许你表示 null 值,这在某些情况下很有用,而基本数据类型不能表示 null。
基本数据类型(如 int、float、double)通常更轻量级,但不提供上述优势。在开发中,你可以根据需要选择使用基本数据类型或 Number 类的对象。通常,基本数据类型在性能上更高效,但 Number 类提供了更多的灵活性和功能,特别适用于需要处理不同数值类型的情况。
Number num1 = 10; // 使用 Integer 类
Number num2 = 3.5; // 使用 Double 类
// 执行加法操作
double result = num1.doubleValue() + num2.doubleValue();
System.out.println("Result: " + result);
3. 常见的方法
- intValue(): 用于将 Number 对象转换为 int 类型。
- doubleValue(): 用于将 Number 对象转换为 double 类型。
- floatValue(): 用于将 Number 对象转换为 float 类型。
- longValue(): 用于将 Number 对象转换为 long 类型。
- byteValue(): 用于将 Number 对象转换为 byte 类型。
- shortValue(): 用于将 Number 对象转换为 short 类型。
- toString(): 用于将 Number 对象转换为字符串表示。
- compareTo(): 用于比较两个 Number 对象的大小。
- valueOf(): 用于创建一个 Number 对象,根据传递的参数的类型来决定创建哪个子类的对象。
public class ValueOfExample {
public static void main(String[] args) {
// 使用 valueOf 创建 Number 对象
Number num1 = Integer.valueOf(10); // 创建一个 Integer 对象
Number num2 = Double.valueOf(3.14); // 创建一个 Double 对象
// 使用方法进行操作
double result = num1.doubleValue() + num2.doubleValue();
System.out.println("Result: " + result);
}
}
4. 常见的 Number 类常量
- Integer.MAX_VALUE 和 Integer.MIN_VALUE: 表示整数的最大值和最小值。
- Double.MAX_VALUE 和 Double.MIN_VALUE: 表示双精度浮点数的最大正数和最小正数。
- Math.PI: 表示圆周率 π。
- Math.E: 表示自然对数的底数 e。
- Long.MAX_VALUE 和 Long.MIN_VALUE: 表示长整数的最大值和最小值。
这些常量可以在数学计算和编程中使用,以提供准确的数值表示。例如,你可以使用 Math.PI 来获取圆周率的值,而不必手动键入其数值。同样,Integer.MAX_VALUE 和 Integer.MIN_VALUE 是用于表示整数范围的有用常量。
double circleArea = Math.PI * radius * radius; // 计算圆的面积,使用 Math.PI 常量
int maxIntValue = Integer.MAX_VALUE; // 获取整数的最大值
long minLongValue = Long.MIN_VALUE; // 获取长整数的最小值
public class IntegerOverflowExample {
public static void main(String[] args) {
int maxValue = Integer.MAX_VALUE;
int minValue = Integer.MIN_VALUE;
// 检查加法是否会溢出
int a = maxValue;
int b = 1;
if (a + b > maxValue) {
System.out.println("Addition will not overflow");
} else {
System.out.println("Addition will overflow");
}
// 检查减法是否会溢出
int x = minValue;
int y = 1;
if (x - y < minValue) {
System.out.println("Subtraction will not overflow");
} else {
System.out.println("Subtraction will overflow");
}
}
}
六. Autoboxing
在Java中,autoboxing是一种自动装箱的过程,它将原始数据类型(如int、double、boolean等)自动转换为相应的包装类对象(如Integer、Double、Boolean等),以便在需要对象的情况下进行操作。这个过程是Java编译器自动执行的,使得代码更易于编写和阅读。
oracle
Autoboxing的主要用途是在原始数据类型和包装类对象之间进行转换,而不需要显式的转换操作。这使得代码更加简洁,减少了手动进行装箱(boxing)和拆箱(unboxing)的需要,提高了代码的可读性。
// Autoboxing: 将原始数据类型自动装箱为包装类对象
Integer num1 = 42; // int自动装箱为Integer
Double num2 = 3.14; // double自动装箱为Double
Boolean flag = true; // boolean自动装箱为Boolean
// Unboxing: 将包装类对象自动拆箱为原始数据类型
int intValue = num1; // Integer自动拆箱为int
double doubleValue = num2; // Double自动拆箱为double
boolean boolValue = flag; // Boolean自动拆箱为boolean
七. the Math class
Math类是Java中的一个数学工具类,它包含了许多用于执行常见数学运算的静态方法。这些方法可以用来执行各种数学操作,例如取整、取绝对值、指数运算、三角函数、对数运算等等。
1. 常量
Math.PI:表示圆周率π的值。
Math.E:表示自然对数的底数e的值。
2. 三角函数
Math.sin(double a):返回a的正弦值。
Math.cos(double a):返回a的余弦值。
Math.tan(double a):返回a的正切值。
3. 四舍五入
Math.abs(double a):返回a的绝对值。
Math.ceil(double a):返回不小于a的最小整数。
Math.floor(double a):返回不大于a的最大整数。
4. 比较函数
Math.max(double a, double b):返回a和b中的较大值。
Math.min(double a, double b):返回a和b中的较小值。
5. 指数和对数运算
Math.exp(double a):返回e的a次方,其中e是自然对数的底数。
Math.log(double a):返回a的自然对数。
Math.pow(double base, double exponent):返回base的exponent次方。
6. 随机数生成
Math.random():返回一个伪随机数,它是一个位于0.0(包括)和1.0(不包括)之间的双精度浮点数。
public class MathExamples {
public static void main(String[] args) {
// 常量示例
double pi = Math.PI;
System.out.println("π的值:" + pi);
// 三角函数示例
double angle = 45; // 以度为单位的角度
double radians = Math.toRadians(angle); // 将角度转换为弧度
double sinValue = Math.sin(radians);
double cosValue = Math.cos(radians);
double tanValue = Math.tan(radians);
System.out.println("sin(45°) = " + sinValue);
System.out.println("cos(45°) = " + cosValue);
System.out.println("tan(45°) = " + tanValue);
// 四舍五入示例
double num = -3.75;
double absValue = Math.abs(num);
double ceilValue = Math.ceil(num);
double floorValue = Math.floor(num);
System.out.println("|-3.75| = " + absValue);
System.out.println("ceil(-3.75) = " + ceilValue);
System.out.println("floor(-3.75) = " + floorValue);
// 指数和对数运算示例
double base = 2.0;
double exponent = 3.0;
double expResult = Math.exp(exponent);
double logResult = Math.log(base);
double powResult = Math.pow(base, exponent);
System.out.println("e^3 = " + expResult);
System.out.println("ln(2) = " + logResult);
System.out.println("2^3 = " + powResult);
// 随机数生成示例
double randomValue = Math.random();
System.out.println("随机数: " + randomValue);
}
}
八. Character Class
Character类是Java中用于封装char类型的类,类似于Integer封装int类型。它提供了一些方法和常量,用于操作字符。
oracle
1. 基本概念
(1)封装char类型
Character类用于封装char类型,使字符具有对象的属性和方法。您可以使用Character类来执行各种字符操作。
(2)属性方法
Character类提供了一些属性方法,用于检查字符的属性,例如:
- isLetter():检查字符是否是字母。
- isDigit():检查字符是否是数字。
- isWhitespace():检查字符是否为空白字符。
- isUpperCase():检查字符是否为大写字母。
- isLowerCase():检查字符是否为小写字母。等等。
(3)转换
您可以使用Character类来将字符转换为字符串,方法是使用toString()。这将返回一个包含单个字符的字符串。
(4)转义序列
在Java中,使用转义序列来表示具有特殊含义的字符,这些字符通常在Java语法中具有特殊用途。例如,\n表示换行符,\t表示制表符等。
char myChar = 'A';
Character charObject = Character.valueOf(myChar);
boolean isLetter = charObject.isLetter(); // 检查字符是否为字母
boolean isDigit = charObject.isDigit(); // 检查字符是否为数字
String charString = charObject.toString(); // 将字符转换为字符串
System.out.println("Is Letter: " + isLetter);
System.out.println("Is Digit: " + isDigit);
System.out.println("Character as String: " + charString);
2. Character类不属于Number类。
Character类用于封装字符数据,而Number类是一个抽象类,用于封装数字数据,如整数和浮点数。它的子类包括Integer、Double、Long等,用于封装不同类型的数字数据。
九. The String Class
String类是Java中用于存储和操作字符串的类。在Java中,字符串是不可变的,这意味着一旦创建了一个字符串,它的内容就不能被更改。
oracle
1. 隐式创建字符串
可以使用双引号将字符串文字括起来,从而创建一个String对象。例如:String x = “foo”; 这将创建一个包含字符串"foo"的String对象。
2. 字符串连接
可以使用加号运算符(“+”)来连接字符串。例如:String y = x + “bar”; 这将创建一个新的字符串"foobar"。
3. String vs. StringBuilder
String对象是不可变的,这意味着每次对字符串进行修改时都会创建一个新的字符串对象,而不会更改原始字符串。如果需要频繁地对字符串进行修改,建议使用StringBuilder类,它是可变的,可以提高性能。
4. 字符串方法
String类提供了许多方法来执行字符串操作,如length()用于获取字符串长度,charAt(index)用于获取指定位置的字符,substring(beginIndex, endIndex)用于提取子字符串,等等。
(1)length(): 返回字符串的长度。
String str = "Hello, World";
int length = str.length(); // length为12
(2)charAt(index): 返回指定索引处的字符。【char】
char character = str.charAt(0); // character为'H'
(3)substring(beginIndex): 返回从指定索引开始到字符串末尾的子字符串。【string】
String sub = str.substring(7); // sub为"World"
(4)substring(beginIndex, endIndex): 返回从起始索引到结束索引之间的子字符串,不包括结束索引处的字符。
String sub = str.substring(7, 12); // sub为"World"
(5)startsWith(prefix): 检查字符串是否以指定前缀开始。
boolean startsWith = str.startsWith("Hello"); // startsWith为true
(6)endsWith(suffix): 检查字符串是否以指定后缀结尾。
boolean endsWith = str.endsWith("World"); // endsWith为true
(7)contains(substring): 检查字符串是否包含指定子字符串。
boolean contains = str.contains("lo,"); // contains为true
(8)indexOf(substring): 返回指定子字符串第一次出现的索引,如果未找到则返回-1。
int index = str.indexOf("World"); // index为7
(9)replace(oldChar, newChar): 替换字符串中的字符。
String replaced = str.replace('o', '0'); // replaced为"Hell0, W0rld"
(10)toUpperCase(): 将字符串转换为大写。toLowerCase(): 将字符串转换为小写。
String upperCase = str.toUpperCase(); // upperCase为"HELLO, WORLD"
String lowerCase = str.toLowerCase(); // lowerCase为"hello, world"
5. 字符串不可变性
由于字符串是不可变的,任何对字符串的更改都会创建新的字符串对象,这可能会导致内存浪费。因此,在处理大量字符串时,要特别小心以避免性能问题。
// 隐式创建字符串
String x = "foo";
// 字符串连接
String y = x + "bar";
// 使用字符串方法
int length = x.length(); // 获取字符串长度
char firstChar = x.charAt(0); // 获取第一个字符
String substring = x.substring(1, 3); // 提取子字符串,包括索引1,不包括索引3
// 字符串不可变性
String original = "Hello";
String modified = original + ", World"; // 创建一个新的字符串
System.out.println(original); // 输出 "Hello"
// 使用StringBuilder进行字符串连接
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("Hello");
stringBuilder.append(", World");
String result = stringBuilder.toString(); // 将StringBuilder转换为String
System.out.println(result); // 输出 "Hello, World"