前言
3倍速看黑马程序员的课速成一下java。感觉java像是简化版的c++,所以学起来比较快。
1.HellowWorld
public class HelloWorld{ //Java源文件只能包含一个公共类,并且其名称必须与文件名相同
public static void main(String[] args){ //一个类只能有一个main方法
System.out.println("HelloWorld");
}
}
2.基础
2.1数据类型
基本数据类型
整型:
byte、short、int、long
long在声明时要在数字后面加上L,因为ava中默认整数型用int接收。
浮点型:
float、double
float在声明时要在数字后面加上F,因为ava中默认浮点型用double接收。
字符型:
char
布尔型:
boolean
引用类型:除了上述基本数据类型之外,Java还有对象引用数据类型,如类、数组、字符串。
2.2键盘录入
import java.util.Scanner;
public class ScannerTest {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in); // 创建一个Scanner对象,用于从标准输入流(通常是键盘)获取输入
System.out.println("请输入一些文本:");
String input = scanner.nextLine(); // 读取用户输入的一行文本
System.out.println("你输入的是: " + input);
scanner.close(); // 关闭Scanner对象,释放相关资源
}
}
2.3运算符
算数运算符
加、减、乘、除、模、自增、自减。和其他语言一样。
注意:字符串和数字、字符相加时,会把数字、字符转化为字符串,然后拼接在一起。
String s = "Hello";
char c = 'W';
s = s + c; // 结果是 "HelloW"
String t = "The sum is ";
int num = 5 + 3;
t = t + num; // 结果是 "The sum is 8",
逻辑运算符
逻辑与(&):不论左边真假,右边都进行运算,并且当只有两边都为真时才为真。
逻辑或(|):不论左边真假,右边都进行运算,并且只有两边都为假时结果才为假。
逻辑非(!):得到与参与运算的布尔值相反的结果。
短路与(&&):如果左边为真,右边参与运算,如果左边为假,那么右边则不参与运算(一假必假)。
短路或(||):如果左边为假,右边参与运算,如果左边为真,那么右边则不参与运算(一真必真)。
逻辑异或(^):如果左右两边的值相同,那么结果为false,如果两边的值不同,那么结果为true。
三元运算符
条件 ? 值1 : 值2
如果条件为真,则整个表达式的值为值1,否则为值2。
3.流程控制语句
条件语句:如if语句、switch语句。这些语句允许基于某些条件执行代码。
循环语句:如for循环、while循环、do-while循环。这些语句允许重复执行一段代码,直到满足特定的终止条件。
转移语句:如break、continue、return。这些语句用于控制程序的执行流程,允许程序跳出循环或跳过循环中的某些迭代。
和c基本一样。
4.方法
在Java中,方法是一种特殊的对象,它代表了一段可重复使用的代码块。方法用于执行特定的操作,并且可以接受输入参数和返回结果。方法的定义包括方法名、参数列表和返回类型。
方法的重载是指在同一个类中定义多个同名方法。通过重载,可以实现同一个方法名执行不同的操作,增强了代码的可读性和可维护性。
方法的重载必须满足以下规则:
-
方法名必须相同。
-
参数列表必须不同,包括参数类型、参数个数或参数顺序。
-
返回类型可以相同也可以不同。
-
方法的重载与访问修饰符、异常列表无关。
public class MethodDemo1 {
public static void main(String[] args) {
//1,2是实参
System.out.println(getSum(1, 2));
System.out.println(getSum(1, 2,3));
System.out.println(getSum(1.1, 2.0));
}
public static int getSum(int a,int b){ //a,b是形参
return (a+b);
}
public static int getSum(int a,int b,int c){
return (a+b+c);
}
public static double getSum(double a,double b){
return (a+b);
}
}
5.面向对象
-
类(Class):类是Java中面向对象编程的基础,它定义了一组具有相同属性和行为的对象的模板。在Java中,类定义了对象的结构和方法。
-
对象(Object):对象是类的实例,它是实际存在的实体。通过类创建的每个对象都有其自身的属性和行为。
-
封装(Encapsulation):封装是面向对象编程的一个重要特性,它隐藏了对象的内部状态并提供了安全的方式来访问对象的属性和方法。在Java中,通过使用访问修饰符(如public、private、protected)来控制对类成员的访问。
-
继承(Inheritance):继承是从已有的类派生出一个新类的过程,新类继承了原始类的属性和方法。通过继承,可以创建更具体的类,并重用和扩展已有的代码。
-
多态(Polymorphism):多态允许一个接口或类被多种形态表现。这意味着同一消息可以被发送到不同类型的数据,而做出不同的动作。在Java中,多态性主要通过接口、继承和重写方法实现。
-
抽象(Abstraction):抽象是通过忽略不必要的细节来关注事物的本质特征的过程。在Java中,抽象可以使用抽象类和接口来实现。抽象类是一种不能被实例化的类,它定义了一组抽象方法和非抽象方法。接口是一种完全抽象的类,它定义了一组抽象方法,但没有实现这些方法。
5.1面向对象基础
以下代码涉及类、对象、封装,包含构造函数、构造函数的重载,成员变量,成员方法。
Phone类是一个JavaBean类
JavaBean类具有以下特点:
-
必须是一个公共类,具有无参数的公共构造器。
-
所有的属性必须是私有的(private),并且只能通过公共的方法(getter和setter方法)进行访问和修改。
-
通常遵循特定的命名规范,如属性名为“属性名”,getter方法名为“get属性名”,setter方法名为“set属性名”。
package Object1;
//一个文件中可以有多个类,但只能有一个public修饰的类,且必须和文件名一样。
public class Phone {
private String band; //成员变量
private double price;
public Phone(){ // 默认构造方法,如果没有构造方法,编译器会提供一个默认的无参数的构造方法。
//创建类对象时如果没有参数,自动调用默认构造方法
}
public Phone(String band, double price){ // 带参数的构造方法,构造方法也可以重载。alt+insert可以快速创建
this.band=band;
this.price=price;
}
public void setBand(String band){
this.band=band; //this用来区分成员变量和局部变量
}
public String getBand(){
return this.band;
}
public void setPrice(double price){
this.price=price; //this用来区分成员变量和局部变量
}
public Double getPrice(){
return this.price;
}
public void play(){
System.out.println(this.band+"开始玩游戏");
}
public void stop(){
System.out.println(this.band+"关机");
}
}
PhoneTest1中实例化了Phone
package Object1;
public class PhoneTest1 {
public static void main(String[] args){
Phone phone1=new Phone();
phone1.setBand("华为Nova11 se");
phone1.setPrice(1999.0);
Phone phone2=new Phone("小米14",3999.0);
System.out.println(phone1.getBand()+" "+phone1.getPrice());
System.out.println(phone2.getBand()+" "+phone2.getPrice());
phone1.stop();
phone2.play();
}
}
内存图
this的本质:方法调用者的地址值
5.2面向对象进阶
static
在Java中,static
是一个关键字,用于创建类的静态成员。静态成员可以是变量(称为静态变量或类变量)、方法(称为静态方法或类方法)或内部类(称为静态内部类)。静态成员属于类本身,而不是类的实例。这意味着,静态成员可以在没有创建类的对象的情况下被访问。
-
静态变量:
-
静态变量在内存中只有一个副本,无论创建多少个类的实例,它们都共享同一个静态变量。
-
静态变量在类加载时初始化,且只初始化一次。
-
静态变量可以通过类名直接访问,无需创建对象。
-
-
静态方法:
-
静态方法属于类,而不是类的实例。
-
静态方法可以直接通过类名调用,无需创建对象。
-
静态方法只能访问静态成员(变量、方法、内部类),不能访问类的非静态成员。
-
-
静态块:
-
静态块(也称为静态初始化块)是在类加载时执行的代码块。
-
静态块常用于初始化静态变量或执行仅需一次的类级操作。
-
静态块在构造函数之前执行,且仅执行一次。
-
使用static
关键字的好处包括:
-
节省内存:因为静态成员在内存中只有一个副本,所以多个对象共享相同的静态数据。
-
方便访问:无需创建对象即可访问静态成员,这在某些情况下(如工具类、单例模式等)非常有用。
-
类级操作:静态方法通常用于执行与类相关的操作,而不是与特定实例相关的操作。
继承
继承的主要特点:
-
代码重用:子类可以继承父类的所有非私有成员(变量和方法),这样就不必重新编写相同的代码。
-
扩展性:子类可以添加新的属性和方法,或者覆盖父类的现有方法来提供不同的功能。
-
层次结构:继承可以创建类的层次结构,其中每个子类都继承其父类的特性,并且可以进一步被其他类继承。
-
多态性:继承是多态性的基础,因为子类对象可以当作父类对象使用(向上转型)。
class Parent {
// 父类的属性和方法
}
class Child extends Parent {
// 子类的属性和方法
}
在上面的例子中,Child
类继承了 Parent
类。这意味着 Child
类将自动获得 Parent
类中定义的所有非私有属性和方法。
继承的限制:
-
Java不支持多重继承,即一个类只能直接继承自一个父类。但是,Java支持接口的多继承,一个类可以实现多个接口。
-
构造函数、私有成员(private)、静态成员(属于类而不属于实例)以及final成员(最终成员,不可被覆盖)不会被继承。
-
子类不能继承父类的构造函数,因为构造函数不属于类的成员,它只是用于初始化对象的一种特殊方法。
成员方法的继承:虚方法表
super
super
是一个关键字,用于引用父类的一个对象。它可以用来访问父类中的属性、方法和构造。使用super
关键字可以调用父类中的方法和属性,以便在子类中重用父类的代码。
当子类定义一个与父类同名的属性时,子类的属性会隐藏父类的属性。
方法重写
在Java中,方法的重写(Override)是子类对父类的允许访问的方法的实现过程进行重新编写, 返回类型和形参都不能改变。这使得子类可以提供其父类方法的不同实现,即子类可以根据需要来改变父类方法的行为。
-
方法签名相同:子类中的重写方法必须与父类中被重写的方法具有相同的方法名称、参数列表和返回类型(可以更小,如父类返回Person,子类可以返回Student)。
-
访问级别不能更严格:子类中的重写方法的访问级别不能低于父类中被重写方法的访问级别。例如,如果父类中的方法是
public
的,那么子类中的重写方法也必须是public
的。 -
静态方法不能被重写:如果父类中的方法是静态的,那么子类中的同名方法实际上是隐藏了父类方法,而不是重写。静态方法属于类,而不属于实例,因此不存在多态性。
-
final方法不能被重写:如果父类中的方法被声明为
final
,那么子类不能重写这个方法。 -
构造方法不能被重写:构造方法不属于继承的范畴,因此不能被重写。子类可以通过调用
super()
来调用父类的构造方法。
可以概括为虚方法表中的方法才能被重写
构造方法是类的特殊方法,用于创建类的对象。子类不能继承父类的构造方法,但可以通过调用super()
关键字来显式地调用父类的构造方法,以便初始化从父类继承的属性。
父类
public class Person{
String name;
int age;
public Person(){
//父类的无参构造
}
public Person(String name,int age){
this.name=name;
this.age=age;
}
}
子类
public class Student{
public Student(){
super(); //默认添加
//子类的无参构造
}
public Student(String name,int age){
super(name,age);
}
}
子类的有参构造函数会自动调用父类的无参构造函数 ,如果父类没有无参数的构造函数,并且也没有在子类中显式地调用父类的构造函数,那么编译器将报错。
多态
一个父类引用可以指向任何其子类对象,而不需要进行类型转换。
编译看左边:编译时会看父类中有没有成员,如果有则编译成功,否则失败。
运行看左/右边:成员变量看左边,成员方法看右边
多态的弊端:不能调用子类特有的方法。
解决方案:强制类型转换为子类。
pet instanceof Dog dog;//输出pet是否为Dog类的实例,并将pet强制转换为Dog对象,存储在dog中
public class Animals {
private String color;
private int age;
//get和set省略
}
public class Dog extends Animals{
public Dog(String color,int age){
super(color,age);
}
@Override
public void eat(String something){
System.out.println(getAge()+"岁的"+getColor()+"颜色的狗在吃"+something);
}
public void lookHome(){
System.out.println(getAge()+"岁的小狗在看家");
}
}
public class Cat extends Animals{
public Cat(String color,int age){
super(color,age);
}
public void eat(String something)
{
System.out.println(getAge()+"岁的"+getColor()+"色的猫在吃"+something);
}
}
public class Person {
private int age;
private String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
//get和set省略
public void keepPet(Animals pet,String something){
if(pet instanceof Dog dog){
System.out.println(this.getAge()+"岁的"+this.getName()+"养了一只"+pet.getAge()+"岁的狗,喂给它吃"+something);
dog.eat(something);
}else if(pet instanceof Cat cat){
System.out.println(this.getAge()+"岁的"+this.getName()+"养了一只"+pet.getAge()+"岁的猫,喂给它吃"+something);
cat.eat(something);
}
}
}
final
在Java中,final
是一个关键字,它可以用来修饰类、方法和变量(包括成员变量、局部变量、静态变量)。final
的含义是“最终的”,一旦被final
修饰,被修饰的实体就具有了不可改变的特性。
-
final
修饰类:当一个类被final
修饰后,这个类就不能被继承了。也就是说,没有其他类能够继承这个类的属性和方法。这在某些情况下是有用的,比如当你想确保某个类的行为不会被修改时。 -
final
修饰方法:当一个方法被final
修饰后,这个方法就不能被覆盖了。也就是说,子类不能重写父类中的这个方法。这可以确保父类的方法在子类中保持不变的行为。 -
final
修饰变量:当一个变量被final
修饰后,这个变量就变成了常量,只能被赋值一次。如果尝试再次修改它的值,编译器就会报错。这对于定义在程序运行过程中不会改变的值非常有用。 -
final修饰引用数据类型:地址值不能改变
代码块
-
非静态构造代码块(实例初始化块):这种代码块在每次创建类的新实例时都会执行,并且在调用任何构造函数之前执行。如果有多个这样的代码块,它们将按照在源代码中出现的顺序执行。(不够灵活)
-
静态构造代码块(静态初始化块):这种代码块只执行一次,当类被加载到内存中时执行。它通常用于初始化静态变量。静态代码块使用
static
关键字声明。
public class Person(){
String name;
static int number;
//非静态构造代码块
{
name="张三";
}
//静态构造代码块
static {
number=100;
}
}
}
抽象类
抽象类是一种特殊的类,它不能被实例化(即不能直接创建对象)。抽象类通常被用作其他类的基类,以提供一些共有的属性和方法,同时定义一些抽象方法让子类去实现。抽象类使用abstract
关键字来声明。
抽象方法是只有声明而没有实现的方法,它使用abstract
关键字来声明,并且没有方法体。抽象方法必须被定义在抽象类中,而子类如果继承了抽象类并且没有实现所有的抽象方法,那么子类也必须声明为抽象类。
强制子类按照父类的格式写
// 抽象类 Animal 的定义
public abstract class Animal {
// 成员变量
private String name;
// 构造方法
public Animal(String name) {
this.name = name;
}
// 抽象方法 makeSound,没有具体实现
public abstract void makeSound();
// 非抽象方法,有具体实现
public void eat() {
System.out.println(name + " is eating.");
}
// Getter 和 Setter 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
// Dog 类继承自 Animal 抽象类
public class Dog extends Animal {
// 构造方法
public Dog(String name) {
super(name);
}
// 实现抽象方法 makeSound
@Override
public void makeSound() {
System.out.println(getName() + " says woof woof.");
}
}
// Cat 类继承自 Animal 抽象类
public class Cat extends Animal {
// 构造方法
public Cat(String name) {
super(name);
}
// 实现抽象方法 makeSound
@Override
public void makeSound() {
System.out.println(getName() + " says meow meow.");
}
}
// 主类,包含 main 方法
public class Main {
public static void main(String[] args) {
// 创建 Dog 对象
Dog dog = new Dog("Buddy");
dog.eat(); // 调用非抽象方法
dog.makeSound(); // 调用抽象方法的实现
// 创建 Cat 对象
Cat cat = new Cat("Whiskers");
cat.eat(); // 调用非抽象方法
cat.makeSound(); // 调用抽象方法的实现
}
}
接口
接口(Interface)是一种完全抽象的类,它只能包含抽象方法的声明以及常量的声明,而不能包含实例字段和实例方法的实现。接口使用interface
关键字来定义,并且可以被类或其他接口实现(使用implements
关键字)。
成员变量的默认修饰:public static final
方法的默认修饰符:public abstract
public abstract interface Swim {
public abstract void swim();
}
public class Dog extends Animal implements Swim{
//重写抽象方法
@Override
public void swim() {
System.out.println("swim");
}
}
类和类的关系:继承关系,只能单继承,不能多继承,但是可以多层继承。
类和接口的实现关系:可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口 。
接口和接口的关系:继承关系,可以单继承,也可以多继承。
从Java 8开始,接口中引入了一种新的机制,允许在接口中定义有方法体的方法,这些方法被称为默认方法(default methods)和静态方法(static methods)。
默认方法:默认方法是接口中的一种具有方法体的方法,它们使用default
关键字进行标记。默认方法提供了接口方法的默认实现,因此实现接口的类不必强制实现这些方法。如果实现类选择不提供这些方法的实现,那么默认方法的实现将被自动继承。默认方法可以通过接口名直接调用,也可以通过实现类的实例调用。
如果类继承了多个接口,多个接口有相同的默认方法,类需要重写该方法。
public interface MyInterface {
// 抽象方法
void abstractMethod();
// 默认方法
default void defaultMethod() {
System.out.println("This is a default method in MyInterface.");
}
}
静态方法:从Java 8开始,接口中还允许定义静态方法。静态方法也是具有方法体的,但它们只能通过接口名直接调用,不能通过实现类的实例或接口变量来调用。静态方法提供了一种在接口级别上执行操作的机制,而不需要依赖于接口的实现。(static不能省略)
public interface MyInterface {
// 静态方法
static void myStaticMethod() {
System.out.println("This is a static method in MyInterface.");
}
}
public class MyClass { //可以不需要implement Myinterface
public static void main(String[] args) {
// 直接使用接口名调用静态方法
MyInterface.myStaticMethod();
}
}
接口的多态
接口的多态性是通过接口引用变量可以指向其任意实现类的对象来实现的。编译看左,运行看右。
// 定义一个接口
public interface Animal {
void makeSound(); // 抽象方法,没有具体实现
}
// Dog类实现Animal接口
public class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("汪汪汪");
}
}
// Cat类实现Animal接口
public class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("喵喵喵");
}
}
// 主类,包含main方法
public class Main {
public static void main(String[] args) {
// 使用Animal接口的引用指向Dog对象,体现了向上转型
Animal animal1 = new Dog();
animal1.makeSound(); // 输出:汪汪汪
// 使用同一个Animal接口的引用指向Cat对象
Animal animal2 = new Cat();
animal2.makeSound(); // 输出:喵喵喵
// 也可以将Animal引用作为方法参数,进一步体现多态性
playWithAnimal(animal1);
playWithAnimal(animal2);
}
// 定义一个方法,参数是Animal类型
public static void playWithAnimal(Animal animal) {
animal.makeSound(); // 这里不知道具体是哪个实现类,但是可以调用makeSound方法
System.out.println("和动物玩耍");
}
}
适配器设计模式
适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一种接口,从而使得原本由于接口不兼容而无法一起工作的类能够协同工作。
假设我们有一个已存在的类Adaptee
,其方法接口不符合我们的需求,我们需要通过适配器Adapter
将其接口转换成我们所需要的接口Target
。
内部类
什么时候用内部类?是其他类的一部分,单独存在没有意义,如人-心脏,车-发动机。
内部类(也称为嵌套类)是定义在另一个类内部的类。它可以是静态的或非静态的。内部类可以访问外部类的所有成员,包括私有成员。
1.成员内部类:它有一个隐含的引用,该引用指向创建它的外部类的实例。所以可以直接调用外部类的成员。外部类要访问内部类的成员,必须要创建对象。
public class Car {
private String model;
private Engine engine;
public Car(String model) {
this.model = model;
this.engine = new Engine();
}
}
// 内部类Engine的定义
public class Engine {
private String type;
public Engine() {
this.type = "Gasoline";
}
public String getType() {
return type;
}
public String getModel()
{
return Car.this.model;
}
}
}
2.静态内部类:用static修饰的成员内部类。
3.局部内部类:局部内部类是在方法内部定义的。局部内部类可以访问其所在方法的局部变量,以及外部类的成员变量和方法。
4.匿名内部类:隐藏了名字的内部类,可以在成员位置,也可以在局部位置。匿名内部类常用于实现接口或继承抽象类,并且只包含一个构造函数和一个匿名类的主体。
public class Test{
//狗只需要用一次,这不需要重写添加一个类,可以直接用匿名内部类
method(
new Animal(){
@override
public void eat(){
//吃骨头
}
}
);
public static void method(Animal a){
a.eat();
}
}
6.字符串
String
以下是String
类的一些关键特性和常用方法:
-
不可变性:Java中的
String
对象是不可变的,即一旦创建了一个String
对象,就不能改变它包含的字符序列。每次对字符串进行修改操作(如连接、替换、截取等),实际上都会创建一个新的String
对象。 -
创建字符串:可以使用直接赋值的方式创建字符串字面量,或者使用
new
关键字通过String
构造函数来创建字符串对象。(字符串相同时直接赋值会节省空间,new不论是否相同都使用内存。直接赋值的地址在串池里,new出来的值在堆里)
String str1 = "Hello"; // 字符串字面量
String str2 = new String("World"); // 使用String构造函数
字符串连接:可以使用+
运算符或concat()
方法来连接两个字符串。
String greeting = "Hello, ";
String name = "World";
String result = greeting + name; // 使用+运算符
String result2 = greeting.concat(name); // 使用concat()方法
字符串比较:使用equals()
方法来比较两个字符串的内容是否相同,而不是使用==
运算符,因为引用数据类型==是比较地址。
String str1 = "Hello";
String str2 = "Hello";
String str3 = "hello";
boolean isEqual = str1.equals(str2); // true
boolean isEqual2 = str1.equalsIgnoreCase(str3); // true 忽略大小写
字符串查找:可以使用indexOf()
或lastIndexOf()
方法来查找一个子字符串在字符串中首次或最后一次出现的位置。
字符串替换:replace()
方法可以替换字符串中所有指定的字符或子字符串,而replaceAll()
方法可以使用正则表达式来替换字符串中的内容。replace(char oldChar, char newChar)
字符串截取:使用substring()
方法可以截取字符串的一部分。substring(int beginIndex, int endIndex)
字符串转换:toUpperCase()
和toLowerCase()
方法可以将字符串转换为大写或小写。
字符串拆分:split()
方法可以根据指定的分隔符将字符串拆分为字符串数组。
格式化字符串:String.format()
方法允许你创建一个格式化的字符串,类似于C语言中的printf
。
字符串长度:length()
方法返回字符串的长度。
字符串遍历:可以使用charAt()
方法来访问字符串中特定位置的字符,或者使用toCharArray()
方法将字符串转换为字符数组进行遍历。
StringBuilder
StringBuilder 是一个可变的字符序列,用于处理字符串。与 String 不同,StringBuilder 对象的内容是可修改的。
//创建 StringBuilder 对象:
StringBuilder sb = new StringBuilder();
//添加字符或字符串:使用 append() 方法向 StringBuilder 添加内容。
sb.append("Hello");
sb.append(" ");
sb.append("World!");
//获取 StringBuilder 的内容:使用 toString() 方法将 StringBuilder 转换为 String。
String result = sb.toString(); // 输出 "Hello World!"
//删除或替换字符:使用 delete() 或 replace() 方法。
sb.delete(0, 5); // 删除从索引0到4的字符
sb.replace(0, 0, "Hi"); // 将索引0处的字符替换为 "Hi"
//其他常用方法:
length(): 返回 StringBuilder 的长度。
capacity(): 返回 StringBuilder 的容量。
charAt(int index): 返回指定索引处的字符。
insert(int index, char c): 在指定索引处插入一个字符。
delete(int start, int end): 删除从 start 到 end(不包括)的字符。
reverse(): 反转 StringBuilder 的内容。
Stringjoiner
StringJoiner用于拼接字符串。它是Java 8中引入的,特别适用于需要拼接多个字符串的场景。
StringJoiner sj = new StringJoiner(", ","[","]"); //间隔符号,开始符号,结尾符号
sj.add("apple");
sj.add("banana");
sj.add("orange");
String result = sj.toString(); // 输出 "[apple, banana, orange]"
扩展
字符串拼接时如果没有变量,编译之后就是拼接之后的结果,会复用串池中的字符串。
有变量参与,每一行拼接都会在内存中创建新的字符串,浪费内存。
7.常用API
Math
Math
是Java中用于数学常数和数学函数的方法类。它提供了一些静态方法,用于进行数学计算,如三角函数、指数、对数、平方根等。
-
Math.round(double a)
:四舍五入方法,将一个浮点数四舍五入为最接近的整数。 -
Math.random()
:生成一个0.0(包含)到1.0(不包含)之间的随机浮点数。 -
Math.sqrt(double a)
:计算一个数的平方根。 -
Math.pow(double a, double b)
:计算a的b次方。 -
Math.abs(double a)
:返回一个数的绝对值。 -
Math.max(double a, double b)
:返回两个数中的最大值。 -
Math.min(double a, double b)
:返回两个数中的最小值。 -
Math.ceil(double a)
:返回大于或等于给定数字的最小整数。 -
Math.floor(double a)
:返回小于或等于给定数字的最大整数。
System
System
类包含了一些与系统相关的实用方法。它提供了如输入/输出流、环境变量和系统属性等功能。
-
System.getProperty(String key)
:获取系统属性。 -
System.getenv(String name)
:获取环境变量。 -
System.out.println(Object x)
:打印输出。 -
System.setOut(PrintStream out)
:设置标准输出流。 -
System.setErr(PrintStream err)
:设置标准错误流。 -
System.currentTimeMillis()
:返回当前时间。 -
System.nanoTime()
:返回最准确的可用系统计时器的当前值,以纳秒为单位。 -
System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
:将一个数组中的元素快速拷贝到另一个数组。 -
System.exit(int status)
:终止当前正在运行的Java虚拟机,参数用作状态码。
Runtime
Runtime
类是Java运行时环境的接口。它允许Java应用程序与运行它们的JVM进行交互。
-
Runtime.getRuntime()
:获取与当前Java应用程序相关的运行时对象。 -
Runtime.exec(String command)
:在单独的进程中执行指定的字符串命令。 -
Runtime.freeMemory()
:返回Java虚拟机中的空闲内存量。 -
Runtime.maxMemory()
:返回Java虚拟机试图使用的最大内存量。 -
Runtime.totalMemory()
:返回Java虚拟机中的内存总
Object
-
Object clone()
:创建并返回此对象的副本。默认浅拷贝,共享引用对象 -
boolean equals(Object obj)
:比较当前对象与指定对象是否相等。 默认比较地址值是否相等,一般要重写 -
int hashCode()
:返回此对象的哈希码值。 -
String toString()
:返回对象的字符串表示形式。默认返回对象的地址,一般要重写 -
void wait()
:使当前线程等待,直到其他线程调用该对象的notify()
或notifyAll()
方法。 -
void notify()
:唤醒在此对象监视器上等待的一个线程。 -
void notifyAll()
:唤醒在此对象监视器上等待的所有线程。
包装类
基本数据类型对应的对象。
Integer:用于包装基本数据类型int
的值。Java允许将基本数据类型自动装箱为对应的包装类对象,例如,将int
值自动装箱为Integer
对象。同样地,也可以将Integer
对象自动拆箱为int
值。
缓存:Java为-128到127之间的整数值提供了一个缓存。当使用这个范围内的值进行装箱时,相同的值会返回相同的Integer
对象引用,不会new新的对象。这被称为"Integer缓存"。
int primitiveInt = 10;
Integer boxedInt = primitiveInt; // 自动装箱
Integer boxedInt2 = new Integer(20); // 显式装箱
int primitiveInt2 = boxedInt2; // 自动拆箱
其他基本数据类型也都有对应包装类。
Arrays
Arrays是一个包含用于操作数组的静态方法的类。
-
sort():对数组进行排序。
-
binarySearch():在已排序的数组中执行二分查找。
-
fill():使用指定的值填充数组。
-
hashCode():为数组返回哈希码。
-
equals():比较两个数组是否相等。
import java.util.Arrays;
public class ArraysExample {
public static void main(String[] args) {
int[] numbers = {5, 2, 8, 3, 1};
Arrays.sort(numbers); // 对数组进行排序
System.out.println(Arrays.toString(numbers)); // 输出排序后的数组
}
}
Lambda表达式
Lambda表达式(也称为闭包)是Java 8引入的一种新特性,它允许将函数作为参数传递给其他函数或赋值给变量。
Lambda表达式主要用于简化代码,简化匿名内部类的书写,并且使代码更加清晰和易于理解,只能简化函数式接口的匿名内部类书写。
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
numbers.forEach((int x) -> System.out.println(x * x));
8.泛型
编译阶段约束操作的数据类型,并进行检查。
在Java中,泛型使用尖括号(<>)表示,并在声明类、接口或方法时指定类型参数。类型参数可以是一个类类型、接口类型或原始类型。在泛型中,类型参数被视为对某个具体类型的占位符,编译器会在编译时进行类型检查和类型推断。
泛型不具备继承性,但是数据具备
泛型类
泛型类是一种可以存储任何类型的类。在Java中,我们可以通过在类名后面添加尖括号<>并在其中指定类型参数来定义泛型类。例如,ArrayList<T>
是一个泛型类,其中T
是一个类型参数。
public class Box<T> {
private T t;
public Box(T t){
this.t=t;
}
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
public class Test {
public static void main(String[] args) {
Box<Integer> b=new Box(2);
}
}
泛型接口
接口的参数类型和返回类型不确定,可以使用泛型接口。
public interface Operator<T> {
public abstract void saveData(E obj);
public abstract E getData();
}
//没有指定具体的泛型类型,默认是Object类型。这里实现接口指定类型<Student>
public class OperatorImpl1 implements Operator<Student> {
@override
public void saveData(Student obj){
}
@override
public Student getData(Student obj){
}
}
//实现类实现了泛型接口,泛型没有指定,可以回到泛型类的使用
public class OperatorImpl2<A> implements Operator<A> {
@override
public void saveData(A obj){
}
@override
public A getData(Student obj){
}
}
public class Test {
public static void main(String[] args) {
OperatorImpl2<Student> operatorImpl2=new OperatorImpl2<>();
}
}
泛型方法
可以处理不同数据类型
public class Test {
public static void main(String[] args) {
show(new Student("zhangsan",18));
}
public static <T> void show(T t) {
System.out.println(t.toString());
}
}
通配符
泛型的通配符在Java中表示为“?”,它可以用于类、接口或方法的泛型参数列表中。通配符“?”表示未知的类型,它表示该位置可以是任何类型。
在Java中,通配符有三种形式:
无边界通配符:<?> 可以代表一切类型
固定上边界通配符:<? extends T> 可以接受T和其子类。
固定下边界通配符:<? super T>,可以接受T和其父类。