抽象类定义与作用抽象方法是使用abstract修饰且不包含具体实现的方法。其语法形式为public abstract 返回类型 方法名(参数列表);抽象方法没有方法体即没有{}内容仅声明方法签名。它主要用于提供一个通用的模板定义一组共有的属性和行为供子类继承并实现具体逻辑。抽象类与抽象方法的关系一个类如果包含至少一个抽象方法那么该类必须声明为抽象类。抽象类可以包含零个或多个抽象方法。。abstract class Animal { protected String name; public Animal(String name) { this.name name; } // 抽象方法子类必须实现 public abstract void makeSound(); // 具体方法可直接使用 public void sleep() { System.out.println(name is sleeping.); } } class Dog extends Animal { public Dog(String name) { super(name); } Override public void makeSound() { System.out.println(Woof! Woof!); } } class Cat extends Animal { public Cat(String name) { super(name); } Override public void makeSound() { System.out.println(Meow! Meow!); } }抽象类不能被实例化只能通过子类创建对象。子类继承抽象类时必须实现所有抽象方法除非子类也声明为抽象类。抽象类可以有构造函数用于初始化公共字段。抽象类支持多态可通过父类引用指向子类对象。接口Interface是Java中一种特殊的引用类型用于定义一组方法的签名但不包含具体实现。它规定了实现类必须提供哪些方法。接口中的所有方法默认为public abstract且不能包含实例变量只能有常量。public interface 接口名称 extends 父类接口1, 父类接口2 { // 常量定义默认为 public static final 数据类型 常量名 初始值; // 抽象方法声明默认为 public abstract 返回类型 方法名(参数列表); // 默认方法default method default 返回类型 默认方法名(参数列表) { // 方法体 } // 静态方法static method static 返回类型 静态方法名(参数列表) { // 方法体 } // 私有方法private method private void 私有方法名() { // 方法体 } }实现接口的类一个类可以通过implements关键字实现一个或多个接口。一个类实现接口时必须实现所有抽象方法否则该类也必须声明为抽象类。public interface Animal { void makeSound(); void move(); }public class Dog implements Animal { Override public void makeSound() { System.out.println(Woof!); } Override public void move() { System.out.println(Running on four legs.); } }实现接口的类可以被当作接口类型引用实现多态Animal animal new Dog(); animal.makeSound(); // 输出: Woof! animal.move(); // 输出: Running on four legs.多个接口的实现一个类可以实现多个接口使用逗号分隔public interface Flyable { void fly(); } public interface Swimmable { void swim(); } public class Duck implements Flyable, Swimmable { Override public void fly() { System.out.println(Duck is flying.); } Override public void swim() { System.out.println(Duck is swimming.); } }内部类基本概念在Java中内部类是指定义在另一个类内部的类。内部类可以访问外部类的所有成员包括私有成员。根据定义位置和使用方式的不同内部类分为四种类型成员内部类、局部内部类、匿名内部类和静态内部类。成员内部类成员内部类是定义在外部类中的普通类与外部类的成员变量和方法处于同一级别。它可以直接访问外部类的任何成员包括私有成员。public class Work { public static void main(String[] args) { // 创建内部类对象的两种方式 OutClass out new OutClass(); OutClass.InClass inner out.new InClass(); inner.show(); OutClass.InClass a new OutClass().new InClass(); a.show(); } } class OutClass { private int age 18; public class InClass { int age 20; public void show() { int age 30; System.out.println(外部类变量 OutClass.this.age); // 外部类变量18 System.out.println(内部类变量 this.age); // 内部类变量20 System.out.println(局部变量 age); // 局部变量30 } } }静态内部类静态内部类是使用static修饰的内部类它不依赖于外部类的实例。因此可以在不创建外部类对象的情况下直接创建静态内部类的实例。public class OuterClass { static class StaticInnerClass { // 静态内部类的内容 } }OuterClass.StaticInnerClass inner new OuterClass.StaticInnerClass();静态内部类不能直接访问外部类的非静态成员只能访问静态成员。局部内部类局部内部类是在方法或代码块中定义的内部类。它的作用域仅限于该方法或代码块内。public class OuterClass { public void method() { final int localVar 30; class LocalInnerClass { public void display() { System.out.println(Local variable: localVar); } } LocalInnerClass inner new LocalInnerClass(); inner.display(); } }局部内部类只能访问外部方法中被声明为final或等效不可变的局部变量。匿名内部类匿名内部类是没有名字的内部类通常用于简化代码特别是在需要实现接口或继承类但只使用一次的情况下。new 父类名或接口名() { // 类体内容方法重写、变量定义等 };public interface Greeting { void sayHello(); } public class Main { public static void main(String[] args) { Greeting greeting new Greeting() { Override public void sayHello() { System.out.println(Hello from anonymous class!); } }; greeting.sayHello(); } }匿名内部类常用于事件监听器、线程创建等场景。String类String 类是 Java 中用于表示字符串的不可变类定义在 java.lang 包中。它封装了一个字符数组用来存储字符串内容。由于其不可变性一旦创建字符串的内容无法更改。字符串的创建方式通过字面量创建String str1 Hello;通过构造方法创建String str2 new String(World); String str3 new String(new char[]{a, b, c});常用方法获取字符串长度int length str.length();获取指定位置字符char ch str.charAt(0);比较字符串内容是否相等推荐使用 equalsboolean isEqual str1.equals(str2);忽略大小写比较boolean isEqualIgnoreCase str1.equalsIgnoreCase(str2);查找子字符串位置int index str.indexOf(world);截取子字符串String sub str.substring(0, 5);替换字符或子字符串String replaced str.replace(a, b); String replacedAll str.replaceAll(old, new);分割字符串String[] parts str.split(,);转换为大写或小写String upper str.toUpperCase(); String lower str.toLowerCase();去除首尾空白字符String trimmed str.trim();判断是否以某前缀或后缀开始/结束boolean startsWith str.startsWith(Hello); boolean endsWith str.endsWith(World);String 的不可变性String 对象一旦创建其内容不能被修改。任何看似“修改”的操作实际上都会生成新的字符串对象。例如String s abc; s s def; // 产生新对象原对象不变这种设计提高了安全性尤其在多线程环境下避免了共享字符串被意外修改的问题。字符串常量池String PoolJava 在堆内存中维护一个特殊的区域——字符串常量池用于存放字面量形式的字符串。当使用字面量创建字符串时如果池中已存在相同内容的字符串则返回池中的引用避免重复创建。String a hello; String b hello; System.out.println(a b); // true指向同一对象使用 new 构造时不会检查常量池总是创建新对象String c new String(hello); String d new String(hello); System.out.println(c d); // false不同对象字符串拼接优化频繁拼接字符串应使用 StringBuilder 或 StringBuffer避免因大量临时对象导致性能下降。StringBuilder sb new StringBuilder(); sb.append(a).append(b).append(c); String result sb.toString();比较字符串的正确方式使用比较的是引用地址仅当两个变量指向同一个对象时才为真。若需比较内容必须使用.equals()。String s1 test; String s2 new String(test); System.out.println(s1 s2); // false System.out.println(s1.equals(s2)); // true数组深入数组拷贝System.arraycopy() 方法System.arraycopy(src, srcPos, dest, destPos, length);src源数组。srcPos源数组的起始位置。dest目标数组。destPos目标数组的起始位置。length要复制的元素数量。int[] original {1, 2, 3, 4, 5}; int[] copy new int[original.length]; System.arraycopy(original, 0, copy, 0, original.length);Arrays.copyOf() 方法Arrays.copyOf(original, newLength);创建一个指定长度的新数组并将原数组的内容复制到新数组中。如果新长度大于原数组多余位置用默认值填充如 0。int[] original {1, 2, 3, 4, 5}; int[] copy Arrays.copyOf(original, original.length);Arrays.copyOfRange() 方法进行部分拷贝Arrays.copyOfRange(original, from, to);从原数组的from索引开始到to索引结束不包含to。返回一个新数组。int[] original {1, 2, 3, 4, 5}; int[] partialCopy Arrays.copyOfRange(original, 1, 4); // [2, 3, 4]clone() 方法进行浅拷贝int[] copy original.clone();对于基本类型数组clone()方法返回一个新数组内容与原数组相同。适用于一维基本类型数组。int[] original {1, 2, 3, 4, 5}; int[] copy original.clone();多维数组的拷贝对于多维数组clone()只进行浅拷贝即只复制外层数组内层数组仍指向原对象。int[][] original {{1, 2}, {3, 4}}; int[][] copy original.clone(); // 此时copy[0] 和 original[0] 指向同一数组修改会影响彼此若需深拷贝需手动遍历并复制每一维int[][] deepCopy new int[original.length][]; for (int i 0; i original.length; i) { deepCopy[i] original[i].clone(); }System.arraycopy()性能最高适合大量数据复制。Arrays.copyOf()/copyOfRange()代码简洁适合一般场景。clone()最简单但仅限于一维基本类型数组。多维数组必须手动实现深拷贝以避免引用共享问题。数组删除在Java中数组是固定长度的数据结构一旦创建便无法直接修改其大小。因此无法直接从数组中删除元素。但可以通过以下几种方式实现“删除”效果使用集合类将数组转换为List利用集合类提供的删除方法再转回数组。import java.util.*; // 原始数组 Integer[] arr {1, 2, 3, 4, 5}; // 转换为列表 ListInteger list new ArrayList(Arrays.asList(arr)); // 删除指定位置的元素例如索引为2 list.remove(2); // 转回数组 arr list.toArray(new Integer[0]); System.out.println(Arrays.toString(arr)); // [1, 2, 4, 5]此方法适用于需要频繁增删操作的场景灵活性高。手动创建新数组适用于删除单个元素通过遍历原数组跳过要删除的元素创建一个新数组。int[] arr {1, 2, 3, 4, 5}; int indexToDelete 2; // 删除索引为2的元素值为3 int[] newArr new int[arr.length - 1]; for (int i 0, j 0; i arr.length; i) { if (i ! indexToDelete) { newArr[j] arr[i]; } } arr newArr; System.out.println(Arrays.toString(arr)); // [1, 2, 4, 5]适用于已知删除位置的情况效率较高。删除指定值的元素多个匹配若需删除所有等于某个值的元素可使用类似方法二的方式。int[] arr {1, 2, 3, 2, 4, 2}; int valueToDelete 2; ListInteger list new ArrayList(); for (int num : arr) { if (num ! valueToDelete) { list.add(num); } } arr list.stream().mapToInt(Integer::intValue).toArray(); System.out.println(Arrays.toString(arr)); // [1, 3, 4]适合删除特定值的所有实例。使用Arrays.copyOfRange简化版当知道要删除的索引时可直接使用Arrays.copyOfRange拷贝部分数组。int[] arr {1, 2, 3, 4, 5}; int indexToDelete 2; int[] newArr Arrays.copyOfRange(arr, 0, indexToDelete); int[] tail Arrays.copyOfRange(arr, indexToDelete 1, arr.length); // 合并两个部分 int[] result new int[newArr.length tail.length]; System.arraycopy(newArr, 0, result, 0, newArr.length); System.arraycopy(tail, 0, result, newArr.length, tail.length); arr result; System.out.println(Arrays.toString(arr)); // [1, 2, 4, 5]适合一次性删除操作。数组扩容在 Java 中原生数组的大小是固定的一旦创建便无法改变。因此当需要动态增加元素数量时必须通过手动实现扩容机制。常见的做法是创建一个更大的新数组并将原数组中的元素复制到新数组中。System.arraycopy() 方法创建一个新的更大容量的数组使用System.arraycopy()方法高效复制原数组内容。public class DynamicArray { private int[] data; private int size; public DynamicArray() { data new int[10]; // 初始容量 size 0; } public void add(int element) { if (size data.length) { // 扩容创建新数组长度为原数组的 1.5 倍 int newCapacity data.length data.length / 2; int[] newData new int[newCapacity]; System.arraycopy(data, 0, newData, 0, data.length); data newData; } data[size] element; } }ArrayList方法内部已实现自动扩容逻辑import java.util.ArrayList; ArrayListInteger list new ArrayList(); list.add(1); list.add(2); // 底层自动处理扩容无需手动干预Arrays工具类数组排序方法使用Arrays.sort()对数组进行排序支持基本类型和对象类型。int[] numbers {64, 34, 25, 12, 22, 11, 90}; Arrays.sort(numbers);支持指定范围排序Arrays.sort(numbers, 1, 5); // 对索引1到4的元素排序数组查找方法使用Arrays.binarySearch()在已排序数组中查找元素。int[] arr {10, 20, 30, 40, 50}; int index Arrays.binarySearch(arr, 30); // 返回2若未找到返回负值表示插入位置。数组比较方法使用Arrays.equals()比较两个数组是否相等。int[] a {1, 2, 3}; int[] b {1, 2, 3}; boolean isEqual Arrays.equals(a, b); // true对于多维数组使用Arrays.deepEquals()int[][] matrix1 {{1, 2}, {3, 4}}; int[][] matrix2 {{1, 2}, {3, 4}}; boolean deepEqual Arrays.deepEquals(matrix1, matrix2); // true数组填充方法使用Arrays.fill()将数组元素设置为指定值。int[] arr new int[5]; Arrays.fill(arr, 7); // 所有元素变为7支持部分填充Arrays.fill(arr, 1, 4, 9); // 索引1到3设为9数组转字符串使用Arrays.toString()将数组转换为可读字符串。int[] arr {1, 2, 3}; String str Arrays.toString(arr); // [1, 2, 3]多维数组二维数组的初始化声明并使用 new 指定大小// 声明一个 3 行 4 列的二维数组 int[][] matrix new int[3][4]; // 可以逐个赋值 matrix[0][0] 1; matrix[0][1] 2; matrix[1][2] 3; // ...直接初始化静态初始化// 初始化一个 2×3 的二维数组 int[][] matrix { {1, 2, 3}, {4, 5, 6} };每一行必须用{}包裹且每行元素数量可以不同即不规则数组混合初始化int[][] matrix new int[3][]; matrix[0] new int[]{1, 2}; matrix[1] new int[]{3, 4, 5}; matrix[2] new int[]{6};使用二维数组保存表格数据直接初始化创建// 声明并初始化一个3行4列的二维数组 String[][] table { {姓名, 年龄, 城市, 职业}, {张三, 25, 北京, 工程师}, {李四, 30, 上海, 设计师} }; // 遍历并输出表格内容 for (int i 0; i table.length; i) { for (int j 0; j table[i].length; j) { System.out.print(table[i][j] \t); } System.out.println(); }动态创建二维数组// 创建一个指定行数和列数的二维数组 int rows 3; int cols 4; String[][] dynamicTable new String[rows][cols]; // 为数组赋值 dynamicTable[0][0] 姓名; dynamicTable[0][1] 年龄; dynamicTable[0][2] 城市; dynamicTable[0][3] 职业; dynamicTable[1][0] 王五; dynamicTable[1][1] 28; dynamicTable[1][2] 广州; dynamicTable[1][3] 教师;处理不规则表格非矩形// 不同行长度不同的情况非规则二维数组 String[][] irregularTable { {产品, 价格}, {手机, 5000, 品牌}, {电脑, 8000, 配置, 重量} };// 使用固定宽度对齐输出 public static void printTable(String[][] table) { for (String[] row : table) { for (String cell : row) { System.out.printf(%-10s, cell); // 左对齐占10个字符宽度 } System.out.println(); } } // 调用方法 printTable(table);冒泡排序冒泡排序是一种简单的排序算法其核心思想是通过重复遍历数组比较相邻元素并根据大小关系进行交换使得较大的元素逐渐“冒泡”到数组的末尾。每一轮遍历都会将当前未排序部分的最大值移动到正确位置。实现方式一基础冒泡排序升序public class BubbleSort { public static void bubbleSort(int[] arr) { int n arr.length; for (int i 0; i n - 1; i) { for (int j 0; j n - i - 1; j) { if (arr[j] arr[j 1]) { // 交换元素 int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; } } } } public static void main(String[] args) { int[] numbers {64, 34, 25, 12, 22, 11, 90}; System.out.println(排序前 java.util.Arrays.toString(numbers)); bubbleSort(numbers); System.out.println(排序后 java.util.Arrays.toString(numbers)); } }实现方式二优化版冒泡排序提前终止当某一轮遍历中没有发生任何交换时说明数组已经有序可以提前结束排序过程。public class OptimizedBubbleSort { public static void bubbleSort(int[] arr) { int n arr.length; for (int i 0; i n - 1; i) { boolean swapped false; for (int j 0; j n - i - 1; j) { if (arr[j] arr[j 1]) { int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; swapped true; } } // 如果本轮没有交换说明已排序完成 if (!swapped) break; } } public static void main(String[] args) { int[] numbers {5, 2, 8, 1, 9}; System.out.println(排序前 java.util.Arrays.toString(numbers)); bubbleSort(numbers); System.out.println(排序后 java.util.Arrays.toString(numbers)); } }降序冒泡排序只需将比较条件从改为即可实现降序排列。if (arr[j] arr[j 1]) { int temp arr[j]; arr[j] arr[j 1]; arr[j 1] temp; }外层循环控制排序轮数最多需要n-1轮。内层循环每次减少一个比较次数因为每轮后最大值已归位。避免越界访问注意j n - i - 1的边界条件。二分查找二分查找是一种在有序数组中查找特定元素的高效算法。其核心思想是每次将搜索范围缩小一半通过比较目标值与中间元素的大小关系决定下一步在左半部分还是右半部分继续查找。适用条件数组必须是有序的升序或降序。支持随机访问如数组不适用于链表等结构。实现方式一递归实现public static int binarySearchRecursive(int[] arr, int target, int left, int right) { if (left right) { return -1; // 未找到 } int mid left (right - left) / 2; if (arr[mid] target) { return mid; } else if (arr[mid] target) { return binarySearchRecursive(arr, target, left, mid - 1); } else { return binarySearchRecursive(arr, target, mid 1, right); } }int[] arr {1, 3, 5, 7, 9, 11}; int index binarySearchRecursive(arr, 7, 0, arr.length - 1); System.out.println(index); // 输出: 3实现方式二迭代实现推荐public static int binarySearchIterative(int[] arr, int target) { int left 0; int right arr.length - 1; while (left right) { int mid left (right - left) / 2; if (arr[mid] target) { return mid; } else if (arr[mid] target) { right mid - 1; } else { left mid 1; } } return -1; // 未找到 }int[] arr {1, 3, 5, 7, 9, 11}; int index binarySearchIterative(arr, 7); System.out.println(index); // 输出: 3使用left (right - left) / 2而非(left right) / 2可防止整数溢出。若数组中有重复元素返回的索引是不确定的取决于具体实现和数据分布。若需查找第一个或最后一个重复元素需对标准二分查找进行扩展。查找插入位置左边界public static int lowerBound(int[] arr, int target) { int left 0; int right arr.length; while (left right) { int mid left (right - left) / 2; if (arr[mid] target) { left mid 1; } else { right mid; } } return left; }该方法返回第一个大于等于target的元素位置可用于插入排序或去重场景。
阅读完成 · 觉得有帮助?