Java(九)nested class,functional interfaces,Lambda Expressions,software complexity,The Number Classes



一. Nested Classes嵌套类

嵌套类(Nested Class),也称为内部类,是在一个类内部定义的类。在 Java 中,你可以在一个类的内部定义另一个类,这个被定义的类就成为嵌套类。嵌套类可以有不同的类型,包括静态嵌套类、成员内部类、局部内部类和匿名内部类。

oracle

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"
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值