方法、类和对象
方法、类和对象
- 方法:类似于其它语言的函数。
- 类:类是一个模板,它描述一类对象的行为和状态。
- 对象:对象是类的一个实例,有状态和行为。
方法
方法的基础用法
方法声明格式:
[修饰符1 修饰符2 …] 返回值类型 方法名(形式参数列表){
Java语句;… … …
}
方法的调用:
对象名.方法名(实参列表)
方法的命名:
- 方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。
- 下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。
方法的重载
方法的重载是指一个类中可以定义多个方法名相同,但参数不同的方法。 调用时,会根据不同的参数自动匹配对应的方法。 构成方法重载的条件:
- 形参类型、形参个数、形参顺序不同
- 只有返回值不同不构成方法的重载
- 只有形参的名称不同,不构成方法的重载
参数传值机制
Java方法中所有参数都是“值传递”,也就是“传递的是值的副本”。 也就是说,我们得到的是“原参数的复印件,而不是原件”。因此,复印件改变不会影响原件。
- 基本数据类型参数的传值:传递的是值的副本。 副本改变不会影响原件。
- 引用类型参数的传值:引用类型指的是“对象的地址”。因此,副本和原参数都指向了同一个“地址”,改变“副本指向地址对象的值,也意味着原参数指向对象的值也发生了改变”。
类
类的定义方法
// 每一个源文件必须有且只有一个public class,并且类名和文件名保持一致!
public class Car {
}
class Tyre { // 一个Java文件可以同时定义多个class
}
class Engine {
}
class Seat {
}
一个类可以包含以下类型变量:
- 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
- 成员变量:(属性,field)成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
- 类变量:类变量也声明在类中,方法体之外,但必须声明为 static 类型。
一个类可以拥有多个方法。
构造方法
构造器也叫构造方法(constructor),用于对象的初始化。
- 构造器是一个创建对象时被自动调用的特殊方法,目的是对象的初始化。
- 构造器的名称应与类的名称一致。Java通过new关键字来调用构造器,从而返回该类的实例,是一种特殊的方法。
- 每个类都有构造方法。如果没有显式地为类定义构造方法,Java 编译器将会为该类提供一个默认构造方法。
- 构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造器里使用return返回某个值。
- 构造方法也可以像普通类一样重载。
public class Puppy{
public Puppy(){
}
public Puppy(String name){
// 这个构造器仅有一个参数:name
}
}
static关键字
在类中,用static声明的成员变量为静态成员变量,也称为类变量。 类变量的生命周期和类相同,在整个应用程序执行期间都有效。它有如下特点:
- 为该类的公用变量,属于类,被该类的所有实例共享,在类被载入时被显式初始化。
- 对于该类的所有对象来说,static成员变量只有一份,被该类的所有对象共享。
- 一般用“类名.类属性/方法”来调用。(也可以通过对象引用或类名(不需要实例化)访问静态成员。)
- 在static方法中不可直接访问非static的成员。
- static修饰的成员变量和方法,从属于类。普通变量和方法从属于对象的。
对象
创建对象
对象是根据类创建的。在Java中,使用关键字 new 来创建一个新的对象。创建对象需要以下三步:
- 声明:声明一个对象,包括对象名称和对象类型。
- 实例化:使用关键字 new 来创建一个对象。
- 初始化:使用 new 创建对象时,会调用构造方法初始化对象。
示例:
public class Puppy{
public Puppy(String name){
//这个构造器仅有一个参数:name
System.out.println("小狗的名字是 : " + name );
}
public static void main(String[] args){
// 下面的语句将创建一个Puppy对象
Puppy myPuppy = new Puppy( "tommy" );
}
}//小狗的名字是 : tommy
访问实例变量和方法
//实例化对象
Object referenceVariable = new Constructor();
//访问类中的变量
referenceVariable.variableName;
//访问类中的方法
referenceVariable.methodName();
this关键字
this的本质就是创建好的对象的地址, 由于在构造方法调用前,对象已经创建。因此,在构造方法中也可以使用this代表“当前对象”。
this最常的用法:
- 在程序中产生二义性之处,应使用this来指明当前对象。普通方法中,this总是指向调用该方法的对象。构造方法中,this总是指向正要初始化的对象。
- 使用this关键字调用重载的构造方法,避免相同的初始化代码。但只能在构造方法中用,并且必须位于构造方法的第一句。
- this不能用于static方法中。
源文件声明规则
- 一个源文件中只能有一个 public 类
- 一个源文件可以有多个非 public 类
- 源文件的名称应该和 public 类的类名保持一致。例如:源文件中 public 类的类名是 Employee,那么源文件应该命名为Employee.java。
- 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。
- 如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。
- import 语句和 package 语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
面向对象的内存分析
Java虚拟机的内存可以分为三个区域:
- 栈stack
- 栈描述的是方法执行的内存模型。每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)。
- JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)。
- 栈属于线程私有,不能实现线程间的共享。
- 栈的存储特性是“先进后出,后进先出”。
- 栈是由系统自动分配,速度快,栈是一个连续的内存空间。
- 堆heap
- 堆用于存储创建好的对象和数组(数组也是对象)。
- JVM只有一个堆,被所有线程共享。
- 堆是一个不连续的内存空间,分配灵活,速度慢。
- 方法区method area(又叫静态区)
- JVM只有一个方法区,被所有线程共享。
- 方法区实际也是堆,只是用于存储类、常量相关的信息。
- 用来存放程序中永远是不变或唯一的内容。(类信息、静态变量、字符串常量等)
内部类
一般情况,我们把类定义成独立的单元。有些情况下,我们把一个类放在另一个类的内部定义,称为内部类(innerclasses)。
内部类可以使用public、default、protected 、private以及static修饰。而外部顶级类(我们以前接触的类)只能使用public和default修饰。
内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类。编译完成后会出现Outer.class和Outer$Inner.class两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。
内部类的分类
-
成员内部类
-
非静态内部类
可以使用private、default、protected、public任意进行修饰。 类文件:外部类$内部类.class
-
非静态内部类必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。
-
非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。
-
非静态内部类不能有静态方法、静态属性和静态初始化块。
-
外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。
-
成员变量访问要点:
- 内部类里方法的局部变量:变量名。
- 内部类属性:this.变量名。
- 外部类属性:外部类名.this.变量名。
-
内部类的访问:
-
外部类中定义内部类:
new Inner()
-
外部类以外的地方使用非静态内部类:
Outer.Inner varname = new Outer().new Inner()
-
-
-
静态内部类
- 当一个静态内部类对象存在,并不一定存在对应的外部对象。 因此,静态内部类的实例方法不能直接访问外部类的实例方法。
- 静态内部类看做外部类的一个静态成员。 因此,外部类的方法中可以通过:“静态内部类.名字”的方式访问静态内部类的静态成员,通过 new 静态内部类()访问静态内部类的实例。
-
-
匿名内部类:
-
适合那种只需要使用一次的类。比如:键盘监听操作等等。
-
匿名内部类没有访问修饰符。
-
匿名内部类没有构造方法。因为它连名字都没有那又何来构造方法呢。
new 父类构造器(实参类表) \实现接口 () { //匿名内部类类体! }
-
匿名内部类的使用
this.addWindowListener(new WindowAdapter(){ @Override public void windowClosing(WindowEvent e) { System.exit(0); } } ); this.addKeyListener(new KeyAdapter(){ @Override public void keyPressed(KeyEvent e) { myTank.keyPressed(e); } @Override public void keyReleased(KeyEvent e) { myTank.keyReleased(e); } } );
-
-
局部内部类
-
作用域只限于本方法
-
对于比较复杂的情况,需要创建一个非公用的类辅助,此即为局部内部类
-
示例
public class Test2 { public void show() { //作用域仅限于该方法 class Inner { public void fun() { System.out.println("helloworld"); } } new Inner().fun(); } public static void main(String[] args) { new Test2().show(); } }
-
Lambda表达式
Lambda表达式相当于对匿名内部类又一次简化,但仅适用于只有一个待实现方法的情况。
示例:
new Thread(()->{//只有run()方法待实现,故可以使用
for(int i=0;i<20;i++){
System.out.println("helloworld");
}
}).start();
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了