惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
腾讯CDC
V
V2EX
Martin Fowler
Martin Fowler
A
About on SuperTechFans
大猫的无限游戏
大猫的无限游戏
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Check Point Blog
博客园 - 【当耐特】
Cisco Talos Blog
Cisco Talos Blog
The Hacker News
The Hacker News
K
Kaspersky official blog
Security Latest
Security Latest
H
Help Net Security
博客园_首页
美团技术团队
Spread Privacy
Spread Privacy
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
G
Google Developers Blog
NISL@THU
NISL@THU
爱范儿
爱范儿
I
Intezer
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
N
News and Events Feed by Topic
P
Privacy International News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Security @ Cisco Blogs
Schneier on Security
Schneier on Security
雷峰网
雷峰网
人人都是产品经理
人人都是产品经理
V
Vulnerabilities – Threatpost
W
WeLiveSecurity
P
Palo Alto Networks Blog
G
GRAHAM CLULEY
Hacker News: Ask HN
Hacker News: Ask HN
I
InfoQ
The Cloudflare Blog
F
Full Disclosure
SecWiki News
SecWiki News
宝玉的分享
宝玉的分享
N
Netflix TechBlog - Medium

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
OOP1:粗通类、对象和方法
Fish4174 · 2026-05-04 · via 博客园_首页

OOP1:粗通类、对象和方法

总结了如何声明一个含有成员变量、构造方法、成员方法的类,如何使用类创建一个对象并访问它的变量,调用它的方法,以及其他关于类的杂项。

一、类、方法和变量的修饰符

修饰符在 Java 中无处不在,声明或定义类、方法和变量也常常用到它。可以说,阅读一个 Java 程序时,最先映入眼帘的往往就是修饰符。因此笔者最先介绍修饰符,以免带来理解困难。

1. 概述

Java 修饰符就是用来定义类、方法和变量权限、特性、状态的关键字,相当于给代码加标签,控制它们能被谁访问、怎么使用、生命周期是什么。

Java 的修饰符分为两大类:访问权限修饰符非访问修饰符。前者决定类、方法和变量能不能被其他类使用,后者控制功能、行为、生命周期。

  • 访问权限修饰符包含:

public(公共)

protected(保护)

default(缺省,通常不写)

private(私有)

  • 非访问修饰符包含:

static(静态)

final(最终,表示固定)

abstract(抽象)

  • 修饰符可以组合使用,例如:

public static final(表示全局常量)

2. 访问权限修饰符

(1) public

  • 全局都能访问,所有类(包括其他包)都能使用。

  • 在其他包使用公共类时,需要先用 import 语句导入。

  • 一个 .java 文件中只能有一个用 public 修饰的公共外部类。

外部类:写在文件最外层的类,而内部类则是被嵌套在外部类内部的类。

(2) protected

  • 同一个包内的所有类都能使用,不同包中只有其子类可以使用。
  • 在其他包的子类使用时,需要先用 import 语句导入。

子类:子类通过关键字 extends ,继承父类所有非私有的属性和方法,形如:

class 子类 extends 父类{}

(3) default

  • 缺省型,不写即可。
  • 只有同一个包内的所有类能使用。

(4) private

  • 只有当前类可以使用。
  • 可使用 getter 让外部间接访问一个私有类型的变量。

(5)总结

修饰符 同类 同包不同类 不同包子类 不同包非子类
public
protected ×
default × ×
private × × ×

(6)修饰类、方法和变量的异同

修饰符 修饰外部类 修饰方法 修饰成员变量
public 可用 可用 可用
protected 不能修饰外部类 可用 可用
default 可用 可用 可用
private 不能修饰外部类 可用 可用

局部变量唯一可用的修饰符是 final ,其余一切修饰符均不能修饰局部变量!

3. 非访问修饰符

(1) static

  • 修饰类:只有内部类可用 static。
  • 修饰方法:静态方法,不用 new 对象,直接“类名.方法()”调用,静态方法内不能用 this 关键字。
  • 修饰变量:静态变量,全类共享,所有对象共用同一个值。

(2) final

  • 修饰类:类不能被继承(无子类)。
  • 修饰方法:方法不能被子类重写。
  • 修饰变量:变量变成常量,赋值后不能修改。

(3) abstract

  • 修饰类:抽象类,不能 new 对象,专门用来被继承。
  • 修饰方法:抽象方法,没有方法体,子类必须重写。
  • 不能修饰变量。

二、调用方法、访问变量

轻声呼唤你的名字。

1. Java 中的方法和变量

  • 不同于 C 语言, C 语言中可以在主函数外定义函数和变量,它们看起来“居无定所”。在 Java 中,方法和变量要么属于类,要么属于对象。不能在类外定义方法和变量。

  • 如果成员变量用 static 修饰,则该变量称为静态变量类变量,否则称为实例变量

  • 如果成员方法用 static 修饰,则该方法称为静态方法类方法,否则称为实例方法

  • 如果一个变量定义在类体内、方法外,用 static 修饰,那么它就是常说的全局变量。它是一种静态变量,属于类本身。

  • 静态变量和静态方法属于类,实例变量和实例方法属于对象(实例)。

  • 若只用 static 方法和 static 变量,不创建对象,数据和方法分离,便能用 Java 写出面向过程风格的程序,适用于实现一些简单的功能。

  • 实例方法能调用实例方法和静态方法,访问实例变量和静态变量;静态方法只能调用静态方法,访问静态变量

2. 如何调用方法、访问变量

罗列常见的访问方式:直呼其名、对象名、类名、 this 关键字、 super 关键字、 getter 访问方法。

(1)直呼其名

常用于访问、调用同类的变量、方法或访问一个局部变量,无法访问、调用另一个无继承关系的类的任何变量、方法,无论该类是不是公共类,在不在同包。

能访问的变量:

  • 局部变量(最优先)
  • 当前类的实例变量(无歧义时)

如果局部变量与实例变量重名,则直呼其名访问的是局部变量。

  • 当前类的静态变量
  • 从父类继承的非私有变量

能调用的方法:

  • 当前类的实例方法
  • 当前类的静态方法
  • 从父类继承的非私有方法

(2)对象名和类名

  • 实例变量、实例方法必须用对象名访问、调用,形如:对象名.变量名,对象名.方法名。

  • 静态变量、静态方法一般用类名访问、调用,形如:类名.变量名,类名.方法名。

  • 如果用同一个类的不同对象名访问该类下的同一个静态变量,它们引用的实际上是同一个变量。

  • 访问权限由变量、方法前的修饰符决定。

(3)this/super 关键字

  • this 表示当前对象本身,可在实例方法或构造方法访问实例成员和静态成员,有以下用途:

    • 解决局部变量与成员变量同名的问题,形如 this. 变量名。
    • 解决方法参数与成员变量同名的问题,形如 this. 变量名。
    • 重载构造方法时,用来调用该类的另一个构造方法,形如 this([参数列表]),必须写在构造方法的第一排。
  • super 可在子类中使用,用来引用当前对象的父类对象,有以下用途

    • 在子类中调用父类中被覆盖的方法,形如 super. 方法名([参数列表])。
    • 在子类的构造方法中调用父类的构造方法,形如 super([参数列表])。
    • 在子类中访问父类中被隐藏的成员变量,形如 super. 变量名。

this/super 关键字无法在静态方法中使用。

(4)getter访问方法

getter 是类中的一个实例成员方法,通过调用 getter ,返回成员变量,达到访问的目的。通常用这种方法实现对私有型成员变量的访问。

三、面向对象程序设计范式

一般在写 Java 程序时,不会用一个写了主方法的类来实例化对象,即实现业务类启动类的分离。业务类中只定义属性和方法,没有 main 。启动类中只包含主方法,负责创建对象并调用其方法。

1. 业务类-类声明

业务类是实现具体业务逻辑的组件,是应用的核心。我们通常会定义若干业务类,并用业务类创建对象,从而满足业务需求。一个类的定义包括两部分:类声明和类体的定义。

类声明

[修饰符] class 类名
{
	//1.成员变量
	//2.构造方法
	//3.成员方法
}

使用 class 关键字定义类。花括号内的部分称为类体。类体中通常包括三部分内容:成员变量成员方法构造方法。构造方法用于创建类实例,成员变量定义对象状态(属性),成员方法定义对象行为。

设计举例

开发一个处理银行业务的应用程序,需要设计一个表示账户的类。一个账户应该有账号、姓名以及余额等属性,它们定义为成员变量。另外,账户应该有取款操作和存款操作,它们定义为成员方法。程序 1-1 定义一个账户类 Account。

程序 1-1 Account.java

package com.fish4174;//包,用于把功能相关的类和接口分组管理

public class Account
{//次行格式YYDS
    //成员变量的定义,private 进行封装,用 getter/setter 进行访问、修改
    private int id;
    private String name;
    private double balance;//余额

    //构造方法
    public Account(){}//默认构造方法
    public Account(int id, String name, double balance)//构造方法重载:带参数构造方法
    {
        this.id = id;
        this.name = name;
        this.balance = balance;
    }

    //访问方法与修改方法
    public int getId()
    {
        return id;
    }
    public void setId(int id)
    {
        this.id = id;
    }
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public double getBalance()
    {
        return balance;
    }
    public void setBalance(double balance)
    {
        this.balance = balance;
    }

    //存款方法
    public void deposit(double amount)
    {
        balance = balance + amount;
        System.out.println("目前账户余额是:" + balance);
    }
    //取款方法
    public void withdraw(double amount)
    {
        balance = balance - amount;
        System.out.println("目前账户余额是:" + balance);
    }
}

编译该程序可得到一个 Account.class 类文件。

2. 启动类

启动类是包含 main 方法的入口类,我们在 main 方法中创建对象、输入参数、调用对象的方法执行操作并得到输出信息。

创建和使用对象

为了使用对象,一般还要声明一个对象名,即声明对象的引用,然后使用 new 运算符调用类的构造方法创建对象。例如,下面两行声明并创建 Account 类的一个实例 myAccount 。

Account myAccount;
myAccount = new Account();

对象的声明和创建对象可以使用一个语句完成。

Account myAccount = new Account();

下面程序 4-2 使用 Account 类创建一个对象并访问、调用它的变量和方法。

程序 1-2 AccountDemo.java

package com.fish4174;

public class AccountDemo
{
    public static void main(String[] args)
    {
        Account myaccount;//声明一个 Account 类型的引用变量
        myaccount = new Account(1001, "Tian Wang", 2000);//调用构造方法创建对象
        myaccount.deposit(5000);//调用对象方法
        myaccount.withdraw(3000);
        //访问对象成员,输出账户信息
        System.out.println("账户ID = " + myaccount.getId());
        System.out.println("姓名 = " + myaccount.getName());
        System.out.println("余额 = " + myaccount.getBalance());
    }
}

运行结果如下。

3. 业务类-类体的定义

(1)成员变量的定义

格式:

[修饰符] 类型 变量名[ = 初值];

(2)构造方法的定义

  • 构造方法也叫构造器,是类的一种特殊方法,作用是创建对象并初始化对象的状态。它和普通方法的区别如下:

    • 构造方法的名称必须与类名相同。
    • 构造方法不能有返回值,也不能返回 void。
    • 构造方法必须在创建对象时用 new 运算符调用。

    格式:

    [public/protected/private]类名([参数列表])
    {
    	//方法体
    }
    
  • 无参数构造方法:如果在定义类时没有为类定义任何构造方法,则编译器自动为类添加一个默认构造方法。默认构造方法是无参数构造方法,方法体为空。

    • 为 Account 类定义无参数构造方法(亦即自动添加的默认构造方法):

      public Account(){}//默认构造方法,不带参数,方法体为空

    • 创建对象:

      Account myaccount = new Account();

      新建对象的成员变量值都被赋予默认值。

  • 带参数构造方法:可在创建对象时就将其成员变量设置为某个值。一旦为类定义了带参数的构造方法,编译器就不再提供默认构造方法。

    • 创建 Account 对象时指定账户 ID 、姓名和余额:

      public Account(int id, String name, double balance)
      {
      	this.id = id;
      	this.name = name;
      	this.balance = balance;
      }
      
    • 创建对象:

      Account account = new Account(1001, "Tina Wang", 2000);

  • 构造方法的重载:构造方法和普通方法都可以重载,所谓重载是名称相同、参数不同的方法。创建对象时,会根据输入参数的数量和类型不同,调用不同的构造方法。

(3)成员方法的定义

  • 方法用于实现对象的动态特征,也是在对象上可完成的操作。方法必须定义在类体内。

    格式:

    修饰符 返回值类型 方法名([形式参数列表])//方法头
    {
    	//方法体
    }
    

    方法的第一行为方法头,包含方法的修饰符、返回值类型、方法名和方法的参数。而方法名、参数个数、参数类型和参数顺序的组合(方法名([形式参数列表]))称为方法签名,它是一个方法区别于其他方法的标签。方法签名将用在方法重载、方法覆盖和构造方法中。

  • 方法的调用:方法的调用主要使用在三种场合:

    • 用对象引用调用类的实例方法。(对象名.方法名)
    • 类中的方法调用本类的其他方法。(直呼其名)
    • 用类名直接调用 static 方法。(类名.方法名)

    要调用类的实例方法,应先创建一个对象,然后通过对象引用调用,如下所示:

    Account myAccount = new Account();
    myAccount.deposit(3000);
    

    如果要调用类的静态方法,通常使用类名调用,如下所示:

    double rand = Math.random();
    
  • 方法重载:方法重载机制允许在一个类中定义多个同名的方法。实现方法重载,要求同名的方法要么参数个数不同,要么参数类型不同,仅返回值不同不能区分重载的方法。方法重载就是在类中允许定义签名不同的方法

    通过方法重载可实现编译时多态(静态多态),编译器根据参数的不同调用相应的方法,具体调用哪个方法是由编译器在编译阶段静态决定的。

  • 方法参数的传递:Java 中方法的参数传递是按值传递,即在调用方法时将实际参数的值复制传递给方法中的形式参数,方法调用结束后实际参数的值并不改变。形式参数是局部变量,其作用域只在方法内部,离开方法后自动释放。

    基本数据类型(如 int, double)的参数和引用数据类型(如类、接口、数组)的参数的传递有所不同。

    • 对于基本数据类型的参数,是将实际参数值复制传递给方法,方法调用结束后,对原来的值没有影响
    • 当参数是引用类型时,实际传递的是引用值,因此在方法的内部有可能改变原来的对象

    下面程序 1-3 演示了方法参数的两种传递,按值传递和按引用传递。

    程序 1-3 PassByValue.java

    package com.fish4174;
    
    public class PassByValue
    {
        public static void changeValue(int num)
        {
            num = 200;
            System.out.println(num);//输出200
        }
        public static void changeValue(Account account0)
        {
            //在方法体中修改账户的余额
            account0.setBalance(10000);
        }
    
        public static void main(String[] args)
        {
            int number = 100;
            changeValue(number);//把number的值100传递给参数num
            System.out.println(number);//输出的number值仍为100,不改变
            Account account = new Account();
            account.setBalance(8000);
            System.out.println(account.getBalance());//输出8000.0
            changeValue(account);//将对象传递给方法,account与参数account0指向同一个对象
            System.out.println(account.getBalance());//输出10000.0
        }
    }
    

    注意 如果方法传递的是不可改变的引用类型对象(如 String对象),对象在方法内部不可能被改变。

四、杂项

1. UML图

类名

————————————————

(访问权限)成员变量名1:类型

(访问权限)成员变量名2:类型

(访问权限)成员变量名3:类型

—————————————————

(访问权限)构造方法([参数名1:类型...])

(访问权限)成员方法名1([参数名1:类型...]):返回值类型

(访问权限)成员方法名2([参数名1:类型...]):返回值类型

访问权限说明:+ 代表 public 成员,- 代表 private 成员,# 代表 protected 成员,不加则代表缺省型成员。

2. 对象的引用赋值

对于基本数据类型的变量赋值,是将变量的值的一个复制赋给另一个变量。例如:

int x = 10;
int y = x;//将x的值10复制给变量y

对象(包括数组等引用数据类型的变量)的赋值是将对象的引用(地址)赋给变量。例如:

Account account = new Account();
Account account2 = account;//将account的引用赋给account2

上面的赋值语句会使 account 和 account2 指向同一个对象。这时如果修改 account 对象的成员变量值,account2 的对应变量值也会被修改。

3.栈区、堆区、方法区

JVM 将内存大致分为三部分:栈区、堆区、方法区。

栈区:存放局部变量的值、方法的参数值,当变量的生存期结束后,系统自动释放栈区内存。

堆区:存放 new 创建的对象和数组。如果一个对象没有引用指向它,它的内存将被回收。

方法区:存放类的成员方法代码。

4. 成员变量默认值

  • 定义在类体内、方法外的变量即是成员变量,若在类的定义中没有为变量赋初值,编译器会为每个成员变量指定一个默认值。

  • 实例变量的默认值使在创建对象时赋予的,静态变量的默认值是在类首次加载时赋予的,且全局只有一份。

引用数据类型的变量默认值为 null,基本数据类型的变量默认值如下表:

变量类型 初始值 变量类型 初始值
byte 0 float 0.0F
short 0 double 0.0D
int 0 boolean false
long 0L char \u0000

5. 局部变量类型推断(var)

在局部变量的类型可推断时,可以用 var 声明之,不必写出具体的类型名。使用 var 进行声明时必须同时赋值(初始化),否则编译器无法推断类型。

应用场景:

  • 简化对象的创建

    var myAccount = new Account();
    

    下面的语句是错误的。

    var myAccount;//错误,此时不能推断myAccount的类型
    
  • 字符串也是引用类型,可用 var

    var name = "Tina Wang";
    
  • 数组也是引用类型,可用 var

    var nums = new int[]{0, 1, 2};
    

    下面的语句是错误的。

    var nums = {0, 1, 2};//错误,不能推断元素类型
    
  • for 循环和增强的 for 循环中也可以用 var 声明变量。

    for(var i = 0; i < number.length; i++)
    {
    	System.out.print(number[i] + " ");
    }
    for(var i : number)
    {
    	System.out.print(i + " ");
    }
    

6. 垃圾回收

对象名存放的是对象的引用。当对象不再被引用时,该对象就会被销毁,其所占的内存空间也会被释放,这个过程称为垃圾回收。这个操作是在后台自动进行的。

对象何时有可能被回收

  • 当一个对象不再被引用时,该对象才有可能被回收。例如:

    Account account = new Account();
    Account account2 = new Account();
    account2 = account;
    

    上面的代码段创建了两个 Account 对象 account、account2 ,然后让 account2 指向 account,这时 account2 原来指向的对象没有任何引用指向它了,也没有任何办法得到或操作该对象了,该对象就有可能被回收了。

  • 通过为对象引用赋 null 值,可以明确删除一个对象的引用。例如

account2 = null;//原来的account2对象可被回收,注意与上面代码的区别
  • 一个对象可能有多个引用,只有在所有的引用都被删除时,对象才有可能被回收。