1.面向对象
1.1 与面向过程区分 了解
Java是一种面向对象的编程语言,与面向过程的编程方式有明显的区别。
-
思维方式:面向对象编程(OOP)是基于对象的概念,强调将问题分解为对象,通过对象之间的交互来解决问题。而面向过程编程(POP)则是基于过程或函数的思维方式,将问题分解为一系列的步骤或函数。
-
封装和抽象:OOP通过封装和抽象来隐藏内部细节,并将相关的数据和行为封装在对象中。这样可以提高代码的复用性、可维护性和安全性。而POP通常直接操作数据,缺乏对数据和功能的封装。
-
继承和多态:继承和多态是OOP的两个重要概念。继承允许一个类继承另一个类的属性和方法,从而实现代码的重用和扩展性。多态允许不同的对象对相同的方法做出不同的响应,提高了代码的灵活性和可扩展性。而在POP中,没有直接支持继承和多态的机制。
-
代码组织结构:OOP中的代码组织以类为单位,将相关的属性和方法封装在类中。每个对象都是类的实例。而在POP中,代码通常以函数或过程为单位,按照一定的顺序执行。
-
编程风格:OOP更注重概念的抽象和模块化设计,使得代码更易于理解和维护。POP更加注重步骤和算法的设计,更适用于简单的、直线的问题。
1.2 Java类与对象的定义
类是现实世界当中具有共同特征的事物进行抽象形成的模板或概念。而对象是实际存在的个体 类:统称——人 对象:具体——你,我,他
类(Class): 在Java中,类是用来描述对象具有的属性和行为的模板或原型
- 属性(成员变量):用来描述对象的状态或特征,例如姓名、年龄等。
- 方法:用来描述对象的行为或操作,例如吃饭、跑步、上厕所等。
- 构造方法:用来初始化对象的特性或状态。——针对属性较多,如普遍年龄30,性别男,身高170等
对象(Object):对象是类的一个具体实例。当根据类创建一个对象时,这个对象会包含类中定义的属性和行为。每个对象都有自己的状态(属性值)以及可执行的行为(方法)。对象是程序中数据和功能的集合体,通过操作对象可以实现对数据的处理和操作。
总结:类 = 属性 + 方法 【状态 + 动作】
1.3 代码解释 类
[修饰符] class 类名 {类体 = 属性 + 方法
}//举例
public class People{//属性 名称public String name; //属性 年龄public int age;//属性 性别public char sex;//方法 行为public String get(String param) {return "值获取为:"+param;}
以上中name、age都是属性,它们都是成员变量中的实例变量,所谓实例变量就是对象级别的变量,这些属性要想访问,必须先创建对象才能访问,不能直接通过类去访问,因为每个人唯一,没有people的单人对象,谈何名字、性别、年龄 【先有人才能赋予其属性】
1.4 Java对象的创建和使用
类定义之后,就可以使用类这个“模板”来创造“对象”了,一个类是可以创建多个对象的哦!
语法:new 类名()
public class Test{public static void main(String[] args) {//创建一个学生对象new Student();//再创建一个学生对象new Student();//创建一个人类对象new People();//==============使用对象更加方便,建议使用变量接收People p1 = new People();People p2 = new People();
//类似 int i=100; String name ="世界你好哦";
//使用 p1.age=100;//给对象p1的年龄赋值 100p2.name="小白";//给对象p2的姓名改为 小白System.out.println("p2的姓名:" + p2.name); p2的姓名:小白System.out.println("p1的年龄:" + p1.age); p1的年龄:100System.out.println("p1的姓名:" + p1.name); p1的姓名:null 因为没赋值为null}
}
1.5 Java 虚拟机JVM的内存管理
Java虚拟机JVM的内存管理-CSDN博客
● 程序计数器 / PC寄存器:
概念:可以看做当前线程执行的字节码指令地址。
特点:线程私有的内存
作用:线程控制,方法调用,异常处理,多线程交互
● java虚拟机栈(重点):
概念:描述的是java方法执行的内存模型。(每个方法在执行的时候会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息。每个方法从调用直至完成的过程,就对应一个栈帧从入栈到出栈的过程。)
特点:线程私有,生命周期和线程相同。这个区域会出现两种异常:StackOverflowError异常:若线程请求的深度大于虚拟机所允许的深度。OutOfMemoryError异常:若虚拟机可以动态扩展,如果扩展是无法申请到足够的内存。
作用:方法调用,异常处理,局部变量存储【Java虚拟机栈用于存储方法中的局部变量,包括基本数据类型、对象引用以及返回值等】
● 本地方法栈:
概念:它与虚拟机栈所发挥的作用是相似的,区别是java虚拟机栈为执行java方法服务,而本地方法栈是为本地方法服务。
特点:线程私有,也会抛出两类异常:StackOverflowError和OutOfMemoryError。
● java堆(重点):
概念:是被所有线程共享的一块区域,在虚拟机启动时创建。
特点:线程共享,存放的是对象实例(所有的对象实例和数组),GC管
理的主要区域。可以处于物理上不连续的内存空间。
● 方法区(重点):
概念:存储已被虚拟机加载的类信息、常量、静态变量,即时编译器编译后的代码等数据。
特点:线程共享的区域,抛出异常OutOfMemory异常:当方法区无法满足内存分配需求的时候。
当.java编译成.class文件后,除了会生成类名、字段、方法等信息外,还有就是常量信息(包含这个java类定义的各种常量字符串和符合引用),这个常量信息就会被放到运行时常量池中。
永久代是JDK7的HotSpot对于方法区的具体实现,元空间(Metaspace)是JDK8对于方法区的具体实现。元空间与永久代之间区别在于
1、元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制
2、符号引用(Symbols)转移到了native heap;字面量(interned strings)转移到了java heap;类的静态变量(class statics)转移到了java heap
之所以把数据存储从永久代转移到堆上,主要是为了尽量将变化和不变的分开,数据在堆上能有更好的垃圾回收效率。
JDK8按照JVM规范的具体实现 【忽略图中的“绿色线程共享,蓝色线程私有”文字】不想改了,以上图线程私有或共享 为参考
总结:方法区存储类的信息,栈中存储方法执行时的栈帧以及局部变量,堆区中主要存储new出来的对象,以及对象内部的实例变量。其中垃圾回收器主要针对的是堆内存,方法区中最先有数据,因为程序执行之前会先进行类加载。栈内存活动最频繁,因为方法不断的执行并结束,不断的进行压栈弹栈操作
代码的执行过程,内存如何变化?下图为例
public class Test{public static void main(String[] args) {int i = 10;People p= new People();}
}
1.进行类加载 [类加载器(ClassLoader)去加载类的字节码文件,创建代表该类的Class对象]
2.调用main主方法,分配栈帧
3.执行int 1= 10,局部变量
4.执行new People(),在堆中创建对象,同时初始化实例变量
5.堆区中人类People对象的内存地址赋值给局部变量p
注意:堆区中“对象”创建完成之后,该对象在堆区当中的内存地址是:0x1111形式,程序中的“=”将这个堆内存地址赋值给p变量,即p变量保存了堆内存对象的内存地址,我们对于这种变量有一种特殊的称呼,叫做“引用”。
对于People p = new People()代码来说,p不是对象,是一个引用,对象实际上是在堆区当中,p变量持有这个对象的内存地址。 对象是啥 ?new 关键字
通过“引用”去访问堆内存中的对象,读取或修改属性数据
1.6 Java构造方法Constructor
概念:一种特殊方法,创建对象实例时进行初始化操作
[修饰符列表] 构造方法名(形式参数列表){构造方法体; }
● 构造方法名和类名一致。
● 构造方法用来创建对象,以及完成属性初始化操作。
● 构造方法返回值类型不需要写,写上就报错,包括void也不能写。
● 可以重载。
● 如果一个类没有显式定义任何构造方法,Java 会为该类提供一个默认的无参构造方法。
注意:不可被继承或重写
public class Person {private String name;private int age;// 无参构造器public Person() {this.name = "Unknown";this.age = 0;}// 带参构造器1public Person(String name, int age) {this.name = name;this.age = age;}// 带参构造器2public Person(String name) {this.name = name;this.age = 0;}// 带参构造器3public Person(int age) {this.age = age;}// 其他方法// ................// 使用带参构造器创建对象
Person person2 = new Person("John", 25); 创建对象,初始化name/age值
}
详解JAVA中的构造方法_java构造方法-CSDN博客
1.7 Java 空指针异常 ——java.lang.NullPointerException
引用为 空 / null 时,访问实例变量导致NullPointerException
异常的抛出
因为在空引用上访问实例变量相当于在一个空对象上尝试访问其属性,而空对象并没有被实例化,因此无法访问其属性。
public class Test{public String name;public static void main(String[] args) {Test example = null;System.out.println(example.name); // 这里会抛出 NullPointerException 异常//===========为了避免这种异常,可以在访问实例变量之前先检查引用是否为空 if (example != null) {System.out.println(example.name);} else {System.out.println("example is null");}}
}
1.8 实例变量是一个引用
当一个类被实例化为对象时,每个对象都会拥有自己的一组实例变量,这些变量存储在对象的内存中。如果实例变量是一个引用类型(如对象、数组等),变量将保存对实际对象的引用,而不是对象本身。
public class Person {
String name; // name 是一个实例变量,存储字符串引用int age;// 基本数据类型,存储的值
public static void main(String[] args) {
Person person1 = new Person(); // 创建一个 Person 对象
person1.name = "Alice"; // 将字符串 "Alice" 的引用赋给 person1 的 name ,存储的 地址值 【字符串对象的内存地址】
person1.age=10; 因为是基本数据类型,存储的为 10 数值
Person person2 = new Person(); // 创建另一个 Person 对象
person2.name = "Bob"; // 将字符串 "Bob" 的引用赋给 person2 的 name 实例变量
}
}
注意: 基本类型——存储数值
引用类型—— 存储内存地址值 而非变量指向的对象本身【此句有点绕举例说明】
如下图1.8中 String 为引用类型,变量name存储的是类似0xyyyy的 内存地址值,而字符串对象本身在方法区中
图1.8 总结:
对象又被称为实例。
实例变量实际上就是:对象级别的变量。public class Person{
int age;
}
假设创建10个人类对象,age变量应该有10个。每个人的age值可以相同,但互不干扰。
所以这种变量被称为对象级别的变量。属于实例变量。实例变量在访问的时候,是必须先创建对象的,没有对象就不能访问实例变量
对象和引用的区别?
对象:是通过关键字"new"创建出来的,在堆内存中存储,并初始化属性。[对象实际上是存储数据的实体。]
引用:是用来访问对象的变量,它存储了 对象在内存中的地址引用可能是 局部变量存放在栈内存中 [在方法中的局部变量],
也可能是 实例变量存放在堆内存中 【类中的成员变量】
总的来说,对象是实际存在的数据结构,而引用则是指向对象的地址的变量。
1.9 Java方法调用时参数的传递问题 ***
方法调用时参数的传递方式可以分为两种:按值传递和按引用传递
-
按值传递(Pass by Value): 按值传递意味着在方法调用时,实际上传递给方法的是变量的值(即变量的副本),而不是变量本身。在方法内部对参数进行修改不会影响原始变量的值。
-
按引用传递(Pass by Reference): 按引用传递意味着在方法调用时,传递给方法的是变量的引用(地址),方法内部对参数的修改会影响原始变量的值。 【虽然传递的是对象引用的副本,但这两个引用实际指向同一个对象】
在 Java 中,方法参数的传递是按值传递的,即传递的是变量的值(副本)
2.0 Java 封装 ***
概念:将 数据和方法 进行组合并限定对其访问的方式
好处举例: 在现实世界当中我们可以看到很多事物都是封装好的,比如“鼠标”,外部有一个壳,将内部的原件封装起来,至于鼠标内部的细节是什么,我们不需要关心,只需要知道鼠标对外提供了左键、右键、滚动滑轮这三个简单的操作。对于用户来说只要知道左键、右键、滚动滑轮都能完成什么功能就行了。
步骤:1.数据私有化 2.提供对外访问的方法来访问私有化的数据
访问对象的某个属性,一般提供两种方法【get方法——访问、set方法——修改】 对象存在才能调用。——实例方法
命名规范:get、set方法名是set + 属性名(属性名首字母大写)
public class Person{
// private 属性私有化private int age;private String name;
//无参构造public Person(){}
// 有参构造public Person(int age, String _name){age= age;name = _name;}
//提供get方法供给外界使用
public int getAge() {return age;}
//提供set方法赋值/修改值public void setage(int aeg) {no = age;}public String getName() {return name;}public void setName(String _name) {name = _name;}
}
注意:有疑问构造方法中已经给属性赋值了,为什么还要提供set方法呢?
构造方法中给属性赋值是在创建对象的时候完成的,当对象创建完毕之后,属性可能还是会被修改的,后期要想修改属性的值,这个时候就必须调用set方法了。
Java一共有四种权限,private (私有),public(公有),Protected(受保护)还有友好型default/friendly。 权限范围如下:
2.1Java中this关键字是什么 ***
概念:在Java中,this
关键字代表当前对象的引用。它可以在类的方法和构造函数中使用,用于引用调用该方法或构造函数的对象。
存储在Java虚拟机堆内存的对象内部,this这个引用保存了当前对象的内存地址指向自身,任何一个堆内存的java对象都有一个this
作用:
- 区分成员变量和局部变量
public class Person {private String name;public void setName(String name) {this.name = name; // 使用this来指代成员变量} }
2.在构造函数中调用其他构造函数
public class Person {private String name;private int age;public Person() {this("Unknown", 0); // 调用另一个构造函数}public Person(String name, int age) {this.name = name;this.age = age;}
}
3.返回当前对象的引用: 在某些情况下,需要返回当前对象的引用,可以使用this
关键字。
public class MyClass {private int value;public MyClass setValue(int value) {this.value = value;return this; // 返回当前对象的引用}
}
注意:this不能出现在带有static的方法当中。
static的方法,直接采用“类名”的方式调用,也就是说static方法执行的过程中是不需要“当前对象”参与的,所以static的方法中不能使用this,因为this代表的就是“当前对象”。
或者说 static属于类的,因为静态方法不属于任何一个实例!
不带static的方法——实例方法。实例方法、实例变量都跟对象有关,必须有对象存在。然后通过“引用”去访问。
在实例方法中可以直接访问当前对象的实例变量,而“this.”是可以省略的
2.2 static 关键字
表示“静态的”,它可以用来修饰变量、方法、代码块等,修饰的变量叫做静态变量,修饰的方法叫做静态方法,修饰的代码块叫做静态代码块。
当一个成员被声明为静态时,它将与类的实例无关,而与类本身相关联。
java中的变量包括:局部变量和成员变量。
在方法体中声明的变量为局部变量,有效范围很小,只能在方法体中访问,方法结束之后局部变量内存就释放了,在内存方面局部变量存储在栈当中。
在类体中定义的变量为成员变量,而成员变量又包括实例变量和静态变量,当成员变量声明时使用了static关键字,那么这种变量称为静态变量,没有使用static关键字称为实例变量,实例变量是对象级别的,每个对象的实例变量值可能不同,所以实例变量必须先创建对象,通过“引用”去访问,而静态变量访问时不需要创建对象,直接通过“类名”访问。实例变量存储在堆内存当中,静态变量存储在方法区当中。实例变量在构造方法执行过程中初始化,静态变量在类加载时初始化
- 静态变量
静态变量(也称为类变量)属于类,而不是类的实例。因此,所有该类的实例将共享相同的静态变量。静态变量可以通过类名直接访问,而无需创建类的实例public class MyClass {public static int count; // 静态变量public static void main(String[] args) {MyClass.count = 5; // 直接通过类名访问静态变量} }
-
静态方法
静态方法属于类而不是类的实例,因此可以直接通过类名调用,无需创建类的实例。静态方法通常用于公共功能,例如工具方法或工厂方法public class MathUtils {public static int add(int a, int b) {return a + b;}public static void main(String[] args) {int sum = MathUtils.add(3, 4); // 调用静态方法} }
-
静态代码块
静态代码块用关键字static
声明,它会在类被加载时执行,并且只会执行一次。public class MyClass {static {System.out.println("This is a static block");}public static void main(String[] args) {// 在这里访问类时,静态代码块将被执行} }
注意事项
- 静态成员可以直接通过类名访问,无需创建类的实例。
- 静态方法内部不能直接访问非静态变量或调用非静态方法,因为它们是与类的实例相关联的。
- 静态成员对于整个类的所有实例是共享的,因此应谨慎使用静态变量,避免滥用导致全局状态混乱。
2.3 Java 继承 ***
一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。通过继承,子类可以获得父类的特性,并且还可以添加自己特有的属性和方法。
定义一个继承关系,在 Java 中使用关键字 extends
。子类使用 extends
关键字后跟父类的名称来声明继承关系
class 类名 extends 父类名{类体;}
public class Animal { // 父类protected String name;public void eat() {System.out.println("Animal is eating.");} }public class Dog extends Animal { // 子类public void bark() {System.out.println("Dog is barking.");} }public class Main {public static void main(String[] args) {Dog dog = new Dog();dog.name = "Tom";dog.eat(); // 继承自父类dog.bark(); // 子类特有的方法} }
注意:
- 子类可以扩展父类的功能,添加自己的属性和方法。
- 子类不能访问父类中被声明为
private
的属性和方法。- 子类可以重写(覆盖)父类的方法,以实现自己特定的行为。
2.3.1 Java方法覆盖—Overriding
指子类重写(覆盖)父类中已经存在的方法。
方法名、返回值和形参都不能改变。外壳不变,核心重写
class Animal {public void makeSound() {System.out.println("Animal makes a sound");}
}class Dog extends Animal {@Overridepublic void makeSound() { // 子类重写父类的方法System.out.println("Dog barks");}
}
//main方法中调用Dog d1= new Dog();d1.makeSound();//输出结果: Dog barks
当该方法被重写之后,子类对象一定会调用重写之后的方法
方法重写的条件:
1.具有继承关系的父子类之间
2.覆盖之后的方法与原方法具有相同的返回值类型、相同的方法名、相同的形式参数列表
注意事项:
- 私有的方法不能被继承,所以不能被重写
- 构造方法不能被继承,所以也不能被重写
- 覆盖之后的方法不能比原方法拥有更低的访问权限,可以更高 [例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected]
- 覆盖之后的方法不能比原方法抛出更多的异常,可以相同或更少
- 方法覆盖只是和方法有关,和 属性\变量 无关
- 父类中继承过来的方法无法满足当前子类业务需求的时候,子类有必要将父类中继承过来的方法进行覆盖/重写。
- 声明为 final 的方法不能被重写
- 声明为 static 的方法不能被重写,但是能够被再次声明
2.3.2 多态
“同一个行为”发生在“不同的对象上”会产生不同的效果
在 Java 中,多态性通常通过继承和方法覆盖\重写来实现。当一个父类引用指向一个子类对象时,根据实际对象类型的不同,调用相同的方法可能会产生不同的行为。这种行为称为动态绑定或后期绑定。
向上转型是指子类型转换为父类型,又被称为自动类型转换
向下转型是指父类型转换为子类型,又被称为强制类型转换
class Animal {public void makeSound() {System.out.println("Animal makes a sound");}
}class Dog extends Animal {@Overridepublic void makeSound() {System.out.println("Dog barks");}
}class Cat extends Animal {@Overridepublic void makeSound() {System.out.println("Cat meows");}
}public class Main {public static void main(String[] args) {Animal dog = new Dog();Animal cat = new Cat();dog.makeSound(); // 输出:Dog barkscat.makeSound(); // 输出:Cat meows}
}
多态性的特点:
- 多态性允许将父类类型的引用指向子类对象。
- 通过方法覆盖,可以实现不同对象对同一消息作出不同响应。
- 多态性提高了代码的灵活性和可扩展性,使得程序更容易维护和扩展。
2.3.3 super ***
super
是一个关键字,用于引用父类的属性和方法,以及调用父类的构造方法。通过 super
关键字,子类可以显式地访问从父类继承而来的成员(属性和方法),并且可以在子类的构造方法中调用父类的构造方法。
super 与 this 对比:
this
● this是一个引用,保存内存地址指向自己。
● this出现在实例方法中,谁调用这个实例方法,this就代表谁,this代表当前正在执行这个动作的对象。
● this不能出现在静态方法中。
● this大部分情况下可以省略,在方法中区分实例变量和局部变量的时候不能省略。
●“this(实际参数列表)”出现在构造方法第一行,通过当前的构造方法去调用本类当中其它的构造方法。
super代表了当前对象中从父类继承过来的那部分特征;并不指向独立的对象,并不是保存某个对象的内存地址[与this不同]
● super和this都可以使用在实例方法当中。
● super不能使用在静态方法当中,因为super代表了当前对象上的父类型特征,静态方法中没有this,肯定也是不能使用super的。
● super也有这种用法:“super(实际参数列表);”,这种用法是通过当前的构造方法调用父类的构造方法。
super作用:
1.访问父类的属性和方法:子类可以使用 super
关键字来访问父类中被隐藏的属性或方法。这在子类中存在与父类同名的属性或方法时特别有用。
2.调用父类的构造方法:子类的构造方法可以使用 super()
来调用父类的构造方法。通过调用父类的构造方法,子类可以初始化从父类继承而来的属性
class Animal {String name;public Animal(String name) {this.name = name;}public void eat() {System.out.println("Animal is eating.");}
}class Dog extends Animal {int age;public Dog(String name, int age) {super(name); // 调用父类的构造方法this.age = age;}public void display() {System.out.println("Name: " + super.name); // 访问父类的属性super.eat(); // 调用父类的方法System.out.println("Age: " + this.age);}
}public class Main {public static void main(String[] args) {Dog dog = new Dog("Tom", 3);dog.display();}
}
注意:父类和子类中有同名实例变量或者有同名的实例方法,想在子类中访问父类中的实例变量或实例方法,则super是不能省略的,其它情况都可以省略
2.4部分补充
1k=1024B /1024 字节
1B/ 1byte=8bit / 8位 位:计算机内部数据存储的最小单位
1T=1024G,1G=1024M,1M=1024KB, 1K=1024B
电脑32位、64位指的是计算机处理器的寻址能力(addressing capacity)。这里的位数表示处理器一次能够处理的二进制数据的位数
32位支持4GB的物理内存,实际上只能使用3GB到3.5GB左右
64位支持超过4GB的物理内存,最大理论上限为18.4 million TB(1TB = 1024 GB)
递归:自己调用自己 多用于部门、单位树结构代码
注意要点:两部分
基线条件(base case)/ 结束条件 当满足这个条件时,递归将停止。
和递归条件(recursive case)。函数内部调用自身的条件。
- 确保递归函数最终能够收敛到基线条件,避免无限循环。
- 控制递归的深度,过深的递归可能导致栈溢出。
- 递归在某些情况下可能不如迭代效率高,因此需谨慎使用
public static int fibonacci(int n) {if (n <= 1) { // 基线条件return n;} else { // 递归条件return fibonacci(n - 1) + fibonacci(n - 2);}}
数组:存储固定大小 元素的数据结构 :
int[] arr = new int[5]; // 创建一个包含 5 个整数的数组 int[] arr = {1, 2, 3, 4, 5}; // 直接初始化数组的元素
- 长度是确定的,一旦创建不可变长度 越界就会报出异常ArrayIndexOutofBounds 【需要动态长度的数据结构,可以考虑使用 ArrayList 或其他集合类】
- 元素必须相同类型
- 元素可以是基本类型 和 引用类型
- 数组变量属于引用类型,数组本身就是对象,每个元素相当于该对象的成员变量。数组对象本身在堆中
多维数组:数组中的元素还是数组。
int[][] matrix = {{1, 2, 3}, {4, 5, 6}}; // 创建一个二维数组并初始化
int a [ ][ ] = new int [2][5]; //创建一个包含2行5列的数组
Arrays类
java.util.Arrays
是一个实用工具类,提供了各种静态方法来操作数组/***排序*/ int[] arr = {3, 1, 4, 1, 5, 9, 2, 6}; Arrays.sort(arr); // 对数组 arr 进行升序排序 System.out.println(Arrays.toString(arr)); // 打印排序后的数组 /***搜索*/ int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9}; int index = Arrays.binarySearch(arr, 5); // 在数组 arr 中搜索元素 5 System.out.println("元素 5 的索引为:" + index); /**数组填充*/ int[] arr = new int[5]; Arrays.fill(arr, 42); // 用值 42 填充数组 arr System.out.println(Arrays.toString(arr)); // 打印填充后的数组 /***数组比较*/ int[] arr1 = {1, 2, 3}; int[] arr2 = {1, 2, 3}; boolean isEqual = Arrays.equals(arr1, arr2); System.out.println("arr1 和 arr2 是否相等:" + isEqual); /**转换为列表*/ String[] arr = {"apple", "banana", "orange"}; List<String> list = Arrays.asList(arr); // 将数组 arr 转换为列表 System.out.println(list);
简单排序算法两者排序:冒泡排序和选择排序
冒泡:基本思想是通过相邻元素之间的比较和交换来逐渐将最大(或最小)的元素移到最后
选择:基本思想是从未排序部分选择最小(或最大)的元素并将其放到已排序部分的末尾
//冒泡排序 public 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 void selectionSort(int[] arr) {int n = arr.length;for (int i = 0; i < n-1; i++) {int minIndex = i;for (int j = i+1; j < n; j++) {if (arr[j] < arr[minIndex]) {minIndex = j;}}int temp = arr[i];arr[i] = arr[minIndex];arr[minIndex] = temp;} }
实际应用中,通常会选择更高效的排序算法,比如快速排序、归并排序等
面向对象面向对象的本质就是:以类的方式组织代码,以对象的组织(封装)数据
对象是具有状态(属性)和行为(方法)的实体,通过定义类来创建对象。
面向对象编程的特点
封装(Encapsulation):封装指的是将数据和对数据进行操作的代码封装在一个对象中,对象对外部提供公共接口,隐藏了内部实现细节,增强了代码的安全性和可维护性。
继承(Inheritance):继承允许创建 子类(派生类、扩展类)从(基类或父类)继承属性和方法。通过继承可以实现代码的重用和层次结构的组织,减少了重复编写代码的工作量。【私有成员—字段+方法,子类不可继承,但是可通过set、get的public方法使用】
多态(Polymorphism):多态允许不同类型的对象对相同的消息作出不同的响应。通过多态性,可以在不知道对象具体类型的情况下调用其方法,提高了代码的灵活性和可扩展性 【多指重写父类方法后的子类方法,父类引用指向子类对象】
定义有参构造之后,如果想使用无参构造,显示的定义一个无参的构造
对象创建关键字 new ep:构造器 Person guoguo = new Person();
封装:属性定义private 私有,外部无法直接访问,提供方法 public 讲解访问和修改继承:extends关键字
Java中类只有单继承,没有多继承!
子类和父类之间,从意义上讲应该具有“is -a”的关系 狗是动物一种类型,狗是动物的子类
“has -a”关系 一个类包含另一个类的实例作为其成员变量,汽车中包含引擎
super 关键字 父类的
1、super调用父类的构造方法,必须在构造方法的第一个2、super必须只能出现在子类的方法或构造方法中!
3、super和this不能同时调用构造方法!
与this区别 子类的
this:本身调用者这个对象(谁调用了它,它就是谁) 本类构造方法
super:代表父类对象的应用
多态中注意事项:
- 方法的多态 ,属性没有多态的
- 父类、子类的类型转换异常 ClassCastException
- 存在条件:继承关系,方法重写,父类引用指向子类对象。
- static方法属于类,不属于实例,子类不能重写,只是可调用使用
- final 常量 子类继承父类时,会继承父类的所有静态成员,包括常量
- private 方法,不能实现多态
- 子类对象赋值父类引用变量,向上转型。父类对象转换子类类型,【父类对象必须实际上是子类实例】。强转前提,最好判断 A instanceof 子类class
注意点:子类的静态变量可隐藏父类的静态变量,非静态也如此。属性名相同就会被隐藏
静态方法只被隐藏不可被重写
注意:1.父类类型的引用来访问实例变量时,访问的是父类中定义的变量,而不是子类中定义的变量。 2.父类类型的引用来调用静态方法时,调用的是父类中定义的方法
final的用途与相关事项:
- 成员变量 初始化后不可修改。修饰引用类型的成员变量,引用对象不可改,但是对象的本身属性可改
- 成员方法 不被子类重写,可被子类直接使用
- 类 修饰的类不能被继承 ,俗称最终类,无子类
类加载的实例化过程 【静态变量和静态代码块只会在类被加载时执行一次】
- 父类的静态变量和静态代码块按照在代码中出现的顺序依次执行。
- 子类的静态变量和静态代码块按照在代码中出现的顺序依次执行。
- 父类的成员变量和非静态代码块按照在代码中出现的顺序依次执行。
- 父类的构造函数执行。
- 子类的成员变量和非静态代码块按照在代码中出现的顺序依次执行。
- 子类的构造函数执行。
方法中形参与实参
- 实参:调用方法时(a)中,a就是实参,因为此时是调用,该参数a有具体值。
- 形参:声明方法时(int a)中,a就是形参,因为该方法待调用,该参数a还没有具体值,等着被赋值。