java基础语知识(8)

类之间的关系

在类之间,最常见的关系有:

  • 依赖(“uses-a”);
  • 聚合(“has-a”);
  • 继承(“is-a”)。
  1. 依赖:一种使用关系,即一个类的实现需要另一个类的协助,使用关系具有偶然性、临时性、非常弱,被使用类的变化会影响到使用类。在 Java 中表现为局部变量、方法的参数或者对静态方法的调用。例如class Driver中方法drive1(Car car)drive2()drive3()分别通过形参、局部变量、静态方法调用体现对Car类的依赖。
  2. 聚合:关联关系的特例,是强关联关系,体现整体与部分的关系,且部分可以离开整体而单独存在,它们有各自的生命周期,部分可属于多个整体对象,也可为多个整体对象共享。在 Java 中一般使用成员变量形式实现,一般用setter方法给成员变量赋值。例如class DriverCar mycar,若赋予 “车是司机财产一部分” 语义,可表示聚合关系。
  3. 继承(泛化):是一种继承关系,表示一般与特殊的关系,指定子类如何获得父类的所有特征和行为。通过关键字extends明确标识。例如class Dog extends Animal,表示Dog类继承自Animal类,Dog类拥有Animal类的属性和方法,还可拥有自己特有的属性和方法。

对象与对象变量

想要使用对象,首先必须先构造对象,并且对其指定初始状态。然后对对象应用方法。

在java程序设计语言中,要使用构造器(constructor, 或称构造函数)构造新实例。构造器是一种特殊的方法,用来构造并初始化对象。

构造器的定义

构造器的名称必须与类名完全相同,并且没有返回类型(连 void 也不能有)。

基本语法如下:

[访问修饰符] 类名([参数列表]) {// 构造器的方法体
}

 构造器的特点

  • 名称与类名相同:构造器的名称必须和所在类的名称一致,这是 Java 语言的规定,用于明确标识这是一个构造器。大小写也需要一致。
  • 没有返回类型:构造器不能声明返回类型,包括 void 也不可以。这是因为构造器的主要目的是创建并初始化对象,而不是返回一个值。
  • 在创建对象时自动调用:当使用 new 关键字创建一个对象时,会自动调用相应类的构造器来完成对象的初始化工作。

对象(Object)

定义

对象是类的一个实例。类是对一类事物的抽象描述,规定了这类事物所具有的属性和行为;而对象则是类在现实世界中的具体个体,它拥有类所定义的属性和行为的具体值。例如,“汽车” 可以看作一个类,而某一辆具体的红色宝马汽车就是 “汽车” 类的一个对象。

创建对象

在 Java 中,使用 new 关键字来创建对象,其一般步骤如下:

  1. 声明类类型的变量:指定要创建对象的类型。
  2. 使用 new 关键字创建对象:调用类的构造器来初始化对象。
class Car {String color;String brand;// 构造器public Car(String color, String brand) {this.color = color;this.brand = brand;}public void showInfo() {System.out.println("This is a " + color + " " + brand + " car.");}
}public class Main {public static void main(String[] args) {// 创建 Car 对象Car myCar = new Car("red", "BMW");myCar.showInfo();}
}

 在上述代码中,Car 是一个类,myCar 是 Car 类的一个对象。通过 new Car("red", "BMW") 调用 Car 类的构造器创建了一个具体的汽车对象,并对其属性进行了初始化。

对象变量(Object Variable)

定义

对象变量是用来引用对象的变量,它存储的是对象在内存中的引用(地址),而不是对象本身。可以把对象变量看作是指向对象的一个 “指针”,通过这个变量可以访问和操作对象的属性和方法。

对象变量的声明和赋值

声明对象变量的语法与声明基本数据类型变量类似,需要指定变量的类型和名称。赋值时,将 new 关键字创建的对象的引用赋给对象变量。

示例代码如下:

class Dog {String name;public Dog(String name) {this.name = name;}public void bark() {System.out.println(name + " is barking!");}
}public class Main {public static void main(String[] args) {// 声明对象变量Dog myDog;// 创建对象并将引用赋值给对象变量myDog = new Dog("Buddy");myDog.bark();}
}

在上述代码中,Dog myDog; 声明了一个 Dog 类型的对象变量 myDogmyDog = new Dog("Buddy"); 将创建的 Dog 对象的引用赋给了 myDog 变量,之后就可以通过 myDog 来调用 Dog 对象的方法。  

对象和对象变量的区别

  1. 存储内容不同

    • 对象:对象是在堆内存中实际分配的一块内存区域,包含了对象的属性值等具体数据。
    • 对象变量:对象变量存储的是对象在堆内存中的引用(地址),它位于栈内存中。
  2. 生命周期不同

    • 对象:对象的生命周期从使用 new 关键字创建开始,直到没有任何对象变量引用它,并且被 Java 的垃圾回收机制回收为止。
    • 对象变量:对象变量的生命周期取决于它的作用域。当对象变量超出其作用域时,它就会被销毁,但对象本身不一定被销毁,只要还有其他对象变量引用它。
  3. 操作方式不同

    • 对象:对象本身不能直接进行操作,需要通过对象变量来访问和操作对象的属性和方法。
    • 对象变量:可以通过对象变量来调用对象的方法、访问对象的属性等。
  • 需要注意的是,对象变量并没有实际包含一个对象,它只是引用一个对象。 
  • 在java中,任何对象变量的值都是对存储在另一个地方的某个对象的引用。

注:很多人误以为 Java 对象变量等同于 C++ 引用。实则不然,C++ 无 null 引用且引用不可赋值。Java 对象变量类似 C++ 对象指针,如 Java 的 Date birthday; 等同于 C++ 的 Date* birthday; ,且二者用 new 初始化语法相近。变量复制后,二者指向同一对象指针,Java 的 null 引用对应 C++ 的 NULL 指针。

this关键字

在 Java 中,this关键字是一个引用,指向当前对象的实例,主要有以下几种用法:

引用当前对象的成员变量

当类中方法的局部变量和成员变量同名时,根据就近原则,方法会优先使用局部变量。若想访问被覆盖的成员变量,则需使用this前缀。例如:

public class Teacher { private String name; private double salary; private int age; public Teacher(String name,double salary,int age) { this.name = name; this.salary = salary; this.age = age; }
}

上述代码中,构造方法的参数与成员变量同名,通过this.namethis.salarythis.age明确操作的是成员变量。 

调用当前对象的其他方法

this关键字可在方法内部调用当前对象的其他方法,能避免与方法参数或局部变量同名的方法名冲突,确保调用的是当前对象的方法。示例如下:

public class Dog { public void jump() { System.out.println("正在执行jump方法"); } public void run() { this.jump(); System.out.println("正在执行run方法"); }
}
访问本类的构造方法

this()用于访问本类的构造方法,且必须是构造方法中的第一条语句。例如:

public class Student { String name; public Student() { this("张三"); } public Student(String name) { this.name = name; } public void print() { System.out.println("姓名:" + name); }
}

无参构造方法Student()中,this("张三")调用了有参构造方法Student(String name)

实现链式调用

在方法返回this关键字,可实现链式调用,即能在同一个对象上连续调用多个方法。示例:

public class Calculator { private int result; public Calculator add(int number) { this.result += number; return this; } public Calculator subtract(int number) { this.result -= number; return this; } public int getResult() { return this.result; }
} 
// 链式调用示例 
Calculator calculator = new Calculator(); 
calculator.add(5).subtract(3); 
int result = calculator.getResult(); 

上述代码中,addsubtract方法都返回this,实现了链式调用。

 

此外,使用this关键字还有一些注意事项:

  • 不能在静态方法中使用,因为静态方法属于类本身,而非任何对象。
  • this关键字的值不能被赋值给另一个变量,因其只是一个引用,不是对象。
  • 应避免滥用,以免影响代码的可读性和可维护性。
  • this可以区分成员变量和局部变量。

构造方法

构造方法注意事项

1. 构造方法的定义- 如果没有定义构造方法,系统将给出一个默认的无参数构造方法。 - 如果定义了构造方法,系统将不再提供默认的构造方法。

2. 构造方法的重载 - 带参构造方法和无参数构造方法,两者方法名相同,但是参数不同,这叫做构造方法的重载。

3. 推荐的使用方式- 无论是否使用,都手动书写无参数构造方法,和带全部参数的构造方法。

无参数构造方法

如果类中没有定义任何构造方法,Java 编译器会自动提供一个默认的无参数构造方法。当然,也可以手动定义无参数构造方法。示例如下:

class Book {String title;int pageCount;// 无参数构造方法public Book() {title = "默认书名";pageCount = 0;}public void displayInfo() {System.out.println("书名: " + title);System.out.println("页数: " + pageCount);}
}public class Main {public static void main(String[] args) {// 创建Book对象时,调用无参数构造方法Book myBook = new Book();myBook.displayInfo();}
}

 在上述代码中,Book类定义了一个无参数构造方法,在创建Book对象时,该构造方法会被调用,将title初始化为 “默认书名”,pageCount初始化为 0。

带全部参数构造方法

带参数的构造方法用于在创建对象时,为对象的成员变量赋初始值。示例如下:

class Person {String name;int age;String address;// 带全部参数构造方法public Person(String name, int age, String address) {this.name = name;this.age = age;this.address = address;}public void showInfo() {System.out.println("姓名: " + name);System.out.println("年龄: " + age);System.out.println("地址: " + address);}
}public class Main {public static void main(String[] args) {// 创建Person对象时,调用带全部参数构造方法Person person = new Person("张三", 25, "北京市");person.showInfo();}
}

这里Person类的构造方法接受nameageaddress三个参数,在创建Person对象时,通过传递相应的参数来初始化对象的成员变量。

构造方法重载

一个类中可以有多个构造方法,只要它们的参数列表不同,这就是构造方法重载。示例如下:

class Circle {double radius;String color;// 无参数构造方法public Circle() {radius = 1.0;color = "红色";}// 带一个参数构造方法public Circle(double radius) {this.radius = radius;color = "蓝色";}// 带两个参数构造方法public Circle(double radius, String color) {this.radius = radius;this.color = color;}public void printInfo() {System.out.println("半径: " + radius);System.out.println("颜色: " + color);}
}public class Main {public static void main(String[] args) {// 使用不同的构造方法创建对象Circle circle1 = new Circle();Circle circle2 = new Circle(2.5);Circle circle3 = new Circle(3.0, "绿色");circle1.printInfo();circle2.printInfo();circle3.printInfo();}
}

 在Circle类中,定义了三个构造方法,分别是无参数、带一个参数、带两个参数的构造方法。通过构造方法重载,可以根据不同的需求,以不同的方式来创建Circle对象。

标准的javabean类

JavaBean 是一种符合特定编程规范的 Java 类,在 Java 开发中用于封装数据和提供访问数据的方法,方便在不同组件间传递数据等。

在java中:

  1. 类是公共的(public):保证其他类能够访问该 JavaBean 类。
  2. 有一个公共的无参构造方法:便于在反射等机制以及框架(如 Spring)创建对象时使用,比如在框架初始化对象实例时,会首先调用这个无参构造方法。
  3. 属性私有(private):对数据进行封装,保证数据的安全性,防止外部直接访问和修改。
  4. 通过公共的 getter 和 setter 方法访问属性:提供了受控的方式来访问和修改私有属性,同时也可以在这些方法中添加业务逻辑,比如数据验证等。
组成部分
  1. 私有属性:用于存储数据,例如:
private String name;
private int age;

上述代码中,name和age就是JavaBean类的私有属性。 

 2. 无参构造方法

public MyBean() {
}

无参构造方法在创建对象时若没有传入参数,会默认初始化对象的属性。

3. getter 方法:用于获取私有属性的值,命名规范是get加上属性名,且首字母大写(对于布尔类型属性,若属性名是is开头,则 getter 方法为is属性名),例如: 

public String getName() {return name;
}
public int getAge() {return age;
}

4.setter 方法:用于设置私有属性的值,命名规范是set加上属性名,且首字母大写,例如:

public void setName(String name) {this.name = name;
}
public void setAge(int age) {this.age = age;
}

 一个完整的JavaBean示例如下:

public class Person {// 私有属性private String name;private int age;// 无参构造方法public Person() {}// getter方法public String getName() {return name;}public int getAge() {return age;}// setter方法public void setName(String name) {this.name = name;}public void setAge(int age) {this.age = age;}
}

在使用时,可以:

public class Main {public static void main(String[] args) {Person person = new Person();person.setName("Alice");person.setAge(25);System.out.println("姓名:" + person.getName() + ",年龄:" + person.getAge());}
}
注意事项
  • 类名需要见名知意。
  • 成员变量使用private修饰。
  • 提供至少两个构造方法: 无参构造方法。 带全部参数的构造方法。
  • 成员方法: 提供每一个成员变量对应的setXxx()/getXxx()。 如果还有其他行为,也需要写上。

Java 内存分配区域

Java 内存主要分为以下几个区域:

  • 栈(Stack):方法运行时所进入的内存,局部变量也是在这里存储。每个方法在执行时会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息。方法执行结束,栈帧就会被销毁。例如,在一个方法中定义的int num = 10;num这个局部变量就存储在栈内存中。
  • 堆(Heap)new出来的对象和数组等都在堆内存中开辟空间并产生地址。堆是 Java 内存管理的核心区域,是被所有线程共享的一块内存区域,其生命周期从 JVM 启动开始,直到 JVM 停止。对象的实例化、内存分配等操作都在堆中进行,比如new Student();创建的学生对象就存放在堆内存中。
  • 方法区(Method Area):字节码文件加载时进入的内存,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。例如HelloWorld.classTest.class等字节码文件在加载时就会进入方法区。另外,像static修饰的静态变量也存储在方法区。
  • 本地方法栈(Native Method Stack):与虚拟机使用的本地方法相关,为 Native 方法服务。比如 Java 调用 C 或 C++ 的本地代码时,相关的内存操作就在本地方法栈进行。
  • 寄存器:用于存储指令、操作数等,是 CPU 内部的高速存储区域,与 Java 内存模型的关系相对间接,主要供 CPU 快速访问数据。

一个对象的内存分配过程(以Student s = new Student();为例)

  1. 加载 class 文件:JVM 首先会查找并加载Student类的字节码文件(.class文件)到方法区,解析类的元数据信息,如类的字段、方法等。
  2. 申明局部变量:在栈内存中声明一个名为s的局部变量,此时它还没有指向任何有效的对象。
  3. 在堆内存中开辟一个空间:使用new关键字在堆内存中为Student对象分配一块内存空间,这块空间用于存储对象的实例变量等数据。
  4. 默认初始化:堆内存中为对象分配的空间会进行默认初始化,比如对于基本数据类型的成员变量,int类型默认初始化为0boolean类型默认初始化为false等;对于引用类型的成员变量,默认初始化为null
  5. 显示初始化:按照类中成员变量定义时的赋值语句进行初始化,例如private int age = 18;,如果有这样的定义,此时age就会被初始化为18
  6. 构造方法初始化:调用Student类的构造方法,对对象进行进一步的初始化操作,构造方法中可以对成员变量进行赋值等操作。
  7. 将堆内存中的地址值赋值给左边的局部变量:把在堆内存中创建的Student对象的地址赋值给栈内存中的局部变量s,此时s就指向了堆内存中的Student对象,后续就可以通过s来操作该对象。

多个对象引用指向同一个对象的内存情况

假设有以下代码:

Student s1 = new Student();
Student s2 = s1;
  • 首先按照上述单个对象创建过程,new Student();在堆内存中创建一个Student对象,同时在栈内存中创建局部变量s1并指向堆中的对象。
  • 执行Student s2 = s1;时,在栈内存中又创建了一个局部变量s2,并将s1中存储的对象地址赋值给s2,这样s1s2都指向了堆内存中的同一个Student对象。此时,如果通过s1修改对象的属性,s2访问该对象时也会看到属性的变化,因为它们指向的是同一个对象。

不同对象的内存情况

当有多个不同对象创建时,比如:

Student s1 = new Student();
Student s3 = new Student();
  • 每次执行new Student();都会在  堆内存中开辟独立的空间创建新的Student对象。
  • 栈内存中分别有s1s3两个局部变量,它们各自指向堆内存中不同的Student对象,这两个对象的属性相互独立,修改s1指向对象的属性不会影响s3指向的对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/21814.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【实战篇】【深度介绍 DeepSeek R1 本地/私有化部署大模型常见问题及解决方案】

引言 大家好!今天我们来聊聊 DeepSeek R1 的本地/私有化部署大模型。如果你正在考虑或者已经开始了这个项目,那么这篇文章就是为你准备的。我们会详细探讨常见问题及其解决方案,帮助你更好地理解和解决在部署过程中可能遇到的挑战。准备好了…

大模型本地部署及本地知识库构建

1、引言 随着AI技术的快速发展和普及,越来越多的LLM开始开源,若想在本地尝试部署大模型和搭建知识库,可以使用ollamaLLMscherry Studio nomic-embed-text的框架来实现,以便于对AI简单应用流程的整体了解。本地部署和知识库的搭建…

在 Ansys Motion 中创建链式伸缩臂的分步指南

介绍 链传动在负载和/或运动要远距离传递的机器中非常多产,例如,在两个平行轴之间。链条驱动系统的设计需要了解载荷传递和运动学如何影响链条张力、轴轴承中的悬臂载荷、轴应力和运动质量等。使用 Ansys Motion,可以轻松回答上述所有问题以…

blender笔记2

一、物体贴地 物体->变换->对齐物体 ->对齐弹窗(对齐模式:反方,相对于:场景原点,对齐:z)。 之后可以设置原点->原点--3d游标 二、面上有阴影 在编辑模式下操作过后,物体面有阴影。 数据-&g…

SPRING10_SPRING的生命周期流程图

经过前面使用三大后置处理器BeanPostProcessor、BeanFactoryPostProcessor、InitializingBean对创建Bean流程中的干扰,梳理出SPRING的生命周期流程图如下

光子集成电路加速边缘AI推理:突破传统NPU的能效比极限

引言:边缘计算的能耗困局 某领先自动驾驶公司采用128核光子张量处理器后,激光雷达点云处理能效比达458TOPS/W,是传统车规级GPU方案的57倍。在16线束LiDAR实时语义分割任务中,光子矩阵乘法单元将特征提取延迟从8.3ms降至0.12ms&am…

【EndNote】WPS 导入EndNote 21

写在前面:有没有人有激活码,跪求! EndNote,在文献管理和文献引用方面很好用。写文章的时候,使用EndNote引入需要的文献会很方便。我目前用的WPS,想把EndNote的CWYW(Cite While You Write&#…

2025.2.23机器学习笔记:PINN文献阅读

2025.2.23周报 一、文献阅读题目信息摘要Abstract创新点网络架构架构A架构B架构C 实验结论后续展望 一、文献阅读 题目信息 题目: Physics-Informed Neural Networks for Modeling Water Flows in a River Channel期刊: IEEE TRANSACTIONS ON ARTIFICI…

SpringBoot 配置文件

介绍 配置文件时用来解决硬编码问题,把可能会发生改变的信息放在一个集中的地方也就说配置文件上,当我们启动某个程序的时候,应用程序会从配置文件中读取数据,并加载运行。 硬编码是指将数据直接嵌入到源代码中,也就…

Redis三剑客解决方案

文章目录 缓存穿透缓存穿透的概念两种解决方案: 缓存雪崩缓存击穿 缓存穿透 缓存穿透的概念 每一次查询的 key 都不在 redis 中&#xff0c;数据库中也没有。 一般都是属于非法的请求&#xff0c;比如 id<0&#xff0c;比如可以在 API 入口做一些参数校验。 大量访问不存…

LeeCode题库第二十八题

28.找出字符串第一个匹配项的下标 项目场景&#xff1a; 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 …

亚马逊AI图像模型Nova深度体验(含源代码)(上)

在本系列的上篇中&#xff0c;我们介绍了如何利用Amazon Nova Canvas进行创意图片内容生成&#xff0c;并使用Amazon Bedrock的InvokeModel API进行文本到图像&#xff08;文生图&#xff09;的生成。并且介绍了Nova Canvas提供的广泛的功能&#xff0c;包括图像修复、画布扩展…

【MySQL】第八弹---全面解析数据库表的增删改查操作:从创建到检索、排序与分页

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】 目录 1 表的增删改查 1.1 Create 1.1.1 单行数据 全列插入 1.1.2 多行数据 指定列插入 1.1.3 插入否则更新 1.1.4 替…

标量化rknn的输入输出向量转换处理

这是一篇技术探索。yolo11模型生成后&#xff0c;我发现它无法在rknn环境正确识别出目标对象。而在宿主机上&#xff0c;或者直接调用.pt转换过的.onnx模型是可以得到正确结果的。这篇文章对应近乎一天的工作。最终的结论就是。这是一个模型量化的问题&#xff0c;与yolo的版本…

边缘安全加速(Edge Security Acceleration)

边缘安全加速&#xff08;Edge Security Acceleration&#xff0c;简称ESA&#xff09;是一种通过将安全功能与网络边缘紧密结合来提升安全性和加速网络流量的技术。ESA的目标是将安全措施部署到接近用户或设备的地方&#xff0c;通常是在网络的边缘&#xff0c;而不是将所有流…

图表控件Aspose.Diagram入门教程:使用 Python 将 VSDX 转换为 PDF

将VSDX转换为PDF可让用户轻松共享图表。PDF 文件保留原始文档的布局和设计。它们广泛用于演示文稿、报告和文档。在这篇博文中&#xff0c;我们将探讨如何在 Python 中将 VSDX 转换为 PDF。 本文涵盖以下主题&#xff1a; Python VSDX 到 PDF 转换器库使用 Python 将 VSDX 转…

两相四线步进电机的步距角为什么是1.8度

机缘 在CSDN查了好多文章&#xff0c;发现都是用公式来解释1.8的步距角&#xff08;Q&#xff1d;360&#xff0f;MZ&#xff09;&#xff0c;因为转子是50齿&#xff0c;4拍一个循环&#xff0c;所以θ360度/&#xff08;50x4&#xff09;1.8度。估计第一次接触步进电机的什么…

Helix——Figure 02发布通用人形机器人控制的VLA:一组神经网络权重下的快与慢双系统,让两个机器人协作干活

前言 过去一周&#xff0c;我花了很大的心思、力气&#xff0c;把deepseek的GRPO、MLA算法的代码解析通透&#xff0c;比如GRPO与PPO的详细对比&#xff0c;再比如MLA中&#xff0c;图片 公式 代码的一一对应 2.20日晚&#xff0c;无意中刷到figure 02发布Helix的一个演示视频…

Unity游戏制作中的C#基础(2)变量与数据类型

1.变量 &#xff08;1&#xff09;变量的定义&#xff1a;变量是用于存储数据的容器。 &#xff08;2&#xff09;变量的作用&#xff1a;在程序运行过程中&#xff0c;我们可以将各种类型的数据存储在变量中&#xff0c;方便后续使用和操作。 &#xff08;3&#xff09;变量…