Java基础知识:对象与类

本文深入讲解面向对象编程(OOP)的核心概念,包括封装、继承、多态性等,阐述对象的三大特性:行为、状态和标识,以及类设计的最佳实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能部分和隐藏的实现部分。(Object Oriented Programming)
  • 在OOP中,不必关心对象的具体实现,只要能够满足用户的需求即可。
  • 在OOP中,将数据放在第一位,然后再考虑操作数据的算法。

 

  • 封装(encapsulation):隐藏数据,不必了解具体实现如何操纵数据。
  • 对象中的数据:实例域。操纵数据的过程:方法
  • 实现封装的关键在于:绝不能让类中的方法直接访问其他类的实例域。
  • 程序仅通过对象的方法与对象数据进行交互
  • OOP的另一原则,可以通过扩展一个类来建立另外一个新的类:继承

 

  • 对象的三个主要特性:行为状态标识
  • 行为:可以对对象施加什么方法
  • 状态:被施加方法时,如何响应。(必须通过调用方法,才可能发生状态改变)
  • 标识:辨别同行为同状态的不同对象。(作为一个类的实例,每个对象的标识永远是不同的)

 

  • 识别的简单规则:在分析问题的过程中寻找名词,而方法对应着动词
  • 在创建类的时候,哪些名词和动词是重要的完全取决于个人的开发经验

 

  • 类之间的关系:依赖聚合继承
  • 依赖(use-a):如果一个类A的方法操纵另一个类B的对象,那么A依赖于B。尽可能将相互依赖的类减至最少。(使得耦合度最小)
  • 聚合(has-a):类A的对象包含类B的对象。
  • 继承(is-a):表示特殊与一般的关系。
  • UML(Unified Modeling Language)绘制类图。

 

  • 对象变量:一个对象变量并没有实际包含一个对象,而仅仅引用了一个对象。可以将Java的对象变量看作C++的对象指针。
  • 局部变量不会自动地初始化为null,而必须通过调用new或者将它们设置为null进行初始化。
  • 所有的Java对象都存储在中。
  • Java中,若使用一个未初始化的指针,运行系统将产生一个运行时错误,而不是生成一个随机的结果
  • 在Java中,必须使用clone方法获得对象的完整拷贝。

 

  • LocalDate类:日历表示法的类。(Date类:用来表示时间点。)将时间和日历分开是一种很好的OOP设计,通常,最好使用不同的类表示不同的概念
  • 更改器方法(mutator method) 与 访问器方法(access method)。在Java中,访问器方法与更改器方法在语法上没有明显的区别
  • Java.time.LocalDate:
  1. static LocalDate now()
  2. static LocalDate of( int year , int month, int day )
  3. int getYear()
  4. int getMonthValue()
  5. int getDayOfMonth()
  6. DayofWeek getDayOfWeek()
  7. LocalDate plusDays( int n )
  8. LocalDate minusDays( int n )
  • 示例程序(构造一个简单的日历,当前的日期用*号标识)
package coreJava_chap4;
import java.time.*;

/*
 *@lastEdited 2020-7-21
 *@author 迷途小书童
 */
public class Test4_1 {
	public static void main( String args[] ) {
		LocalDate thisDate = LocalDate.now();
		int thisYear = thisDate.getYear();
		int thisMonth = thisDate.getMonthValue();
		int today = thisDate.getDayOfMonth();
		
		LocalDate curDate = LocalDate.of( thisYear, thisMonth, 1 );
		int day = curDate.getDayOfWeek().getValue();
		
		System.out.println("Mon Tue Wed Thu Fri Sat Sun ");
		
		for( int i = 1; i < day; i++ )
			System.out.print("    ");
		
		while( curDate.getMonthValue() == thisMonth ) {
			System.out.printf("%3d", curDate.getDayOfMonth());
			if( curDate.getDayOfMonth() == today ) System.out.print("*");
			else System.out.print(" ");
			curDate = curDate.plusDays(1);
			if( curDate.getDayOfWeek().getValue() == 1 ) 
				System.out.println();
		}
		if( curDate.getDayOfWeek().getValue() != 1 ) System.out.println();
	}
}

 

 

  • 主力类:(workhorse class)。通常,这些类没有main方法,却有自己的实例域和实例方法。
  • 文件名必须与public类的名字相匹配。
  • 一个源文件中,只能有一个公有类,但可以有任意数目的非公有类。
  • 构造器:与类同名 至少一个 参数不限 无返回值 总是伴随着new操作一起调用。
  • 不要在构造器中定义与实例域重名的局部变量。
  • 关键字this表示隐式(implict)参数。
  • 访问器)如果需要返回一个可变对象的引用,应首先对它进行克隆。否则就可能通过这个引用改变对象的私有状态

 

  • 一个方法可以访问所属类的所有对象的私有数据,而不仅限于访问隐式参数的私有特性。
  • 私有方法。(辅助方法)若用其他方式代替私有方法的实现,私有方法可以放心的删去。
  • 若实例域定义为final,那么构建对象的时必须初始化这样的域。final实例域一般应用于基本类型不可变的类
  • 对于被final定义的对象示例域,对象是可变的,但是对象引用不可变
  • 静态域与静态方法:关键字static表示该域或者方法是属于类的,而不是属于任何独立的对象。
  • 静态方法:无隐式参数,不使用任何对象。两种情况下使用静态方法:1.不需访问对象状态 2.只需访问静态域
  • 静态方法的另一常见用途:工厂方法。工厂方法相比于构造器的优势:1.构造器必须与类名同 ,构造含义更清晰 2.可以返回子类的对象示例。
  • Java中,总是采用按调用。(call by value)。所以,1.一个方法不能修改一个基本数据类型的参数 2.一个方法可以改变对象参数的状态 3.一个方法不能让对象参数引用一个新的对象。

 

  • 重载。方法的签名:方法名+参数类型。
  • 默认域初始化:如果在构造器中没有显示地给域赋值,那么就会被自动赋值为默认值(0,false, null)
  • 如果没有编写构造器,那么系统会提供一个无参数的构造器
  • 显式域初始化:可以在类定义中,直接将一个值赋给任何域(直接定义赋值初始化),也可以调用方法对域进行初始化。
  • 构造器可以利用this指针调用另一个构造器。
  • 初始化数据域的三种机制:1.构造器 2.声明中赋值 3.初始化块(非必须,不常见)
  • 调用构造器的具体处理步骤:1.所有数据初始化成默认值 2.依次处理 域初始化语句 、 初始化块 3.构造器语句
  • 如果对类的静态域进行的初始化比较复杂,那么可以使用静态的初始化块
//静态的初始化块示例
static
{
    //Java.util.Random
    Random generator = new Random();
    nextId = generator.nextInt(10000);
}

 

 

  • 对象析构域finalize方法:
  1. Java不支持析构器
  2. 可以为任一个类添加finalize方法,finalize方法将在垃圾回收器清除对象之前调用。但不要依赖于使用finalize,因为不能够具体确定什么时候会调用这个finalize方法。
  3. 如果某个资源需要在使用完毕后立刻被关闭,那么就需要由人工来管理。对象用完时,可以应用一个close方法来完成相应的清理操作。

 

  • Java允许使用包(package)将类组织起来。将自己的代码与别人提供的代码库分开管理。
  • 使用包的主要原因是确保类名的唯一性同类名但是放置于不同的包,不会发生冲突。从编译器的角度出发,嵌套的包之间无任何关系。
  • 所有标准的Java包都处于 java 和 javax 包层次中。
  • 一个类可以使用所属包中的所有类,以及其他包中的公有类。
  • 只能用*导入一个包。
  • import还可以导入静态方法静态域的功能,程序中使用可以省略包名。但是如果命名发生冲突,那么包名就不可以省略。
  • 编译器不检查目录结构,如果包与目录不匹配,虚拟机就找不到类。
  • 禁止加载用户自定义的、包名以"java."开头的类。
  • 包作用域:1.public可以被任意的类使用。 2.private只能被定义它们的类使用(本类使用) 3.没有指定public或者private的,可以被同包中所有方法访问。

 

  • 注释的插入:
  1. 类注释:必须放在import语句之后,类定义之前
  2. 方法注释:所描述的方法之前
  3. 域注释:只需对公有域(通常是静态常量)建立文档
  4. 通用注释
  5. 包与概述注释

 

  • 类设计技巧:
  1. 一定要保证数据私有。
  2. 一定要对数据初始化。
  3. 不要在类中使用过多的基本类型(如果某些基本类型存在关联,则用一个类将它们管理起来)。
  4. 不是所有的域都需要独立的域访问器和域修改器。
  5. 将职责过多的类进行分解。
  6. 类名和方法名要体现它们的职责。
  7. 优先使用不可变的类(若多个线程试图同时更新一个对象,就会发生并发更改,结果不可预料)

 

  • 示例程序4-2:创建Employee类员工对象,每个员工加薪10%,打印每个员工的信息。
package coreJava_chap4;

import java.time.LocalDate;
import static java.lang.System.*;
/*
 *@lastEdited 2020-7-24
 *@author 迷途小书童
 */
public class Test4_2 {
	public static void main( String args[] ) {
		Employee[] staff = new Employee[3];
		staff[0] = new Employee( "Jack", 3000, 2002, 11, 10 );
		staff[1] = new Employee( "Dick", 5000, 2012, 2, 24 );
		staff[2] = new Employee( "Wade", 8000, 2005, 3, 18 );
		
		for( Employee e : staff )
			e.raiseSalary(10);
		
		for( Employee e : staff )
			out.println(e);		
	}
}
class Employee {
	private String name;
	private double salary;
	private LocalDate hireDay;
	
	
	Employee( String name, double salary, int year, int month, int day ){
		this.name = name;
		this.salary = salary;
		hireDay = LocalDate.of( year, month, day );
	}
	
	public String getName()
	{
		return name;
	}
	
	public double getSalary()
	{
		return salary;
	}
	
	public LocalDate getHireDay()
	{
		return hireDay;
	}
	
	public void raiseSalary( double byPercent )
	{
		double add = salary * byPercent /100;
		salary += add;
	}
	
	public String toString()
	{
		String res = "";
		res = res + "name: " + name + ", salary: " + salary + ", hireDay: "+ hireDay.toString();
		return res;
	}
}

 

  • 示例程序:(设置静态与非静态的初始化块,并用不同的构造器构造三个员工对象,打印信息)
package coreJava_chap4;

import java.util.*;
import static java.lang.System.*;
/*
 *@lastEdited 2020-7-24
 *@author 迷途小书童
 */
public class Test4_5 {
	public static void main(String args[] ) {
		Employee[] staff = new Employee[3];
		staff[0] = new Employee("Jack",8000);
		staff[1] = new Employee( 5000 );
		staff[2] = new Employee();
		
		for( Employee e : staff ) {
			out.println( e );
		}
			
	}
}

class Employee{
	private static int nextId;
	
	private String name = "";
	private int id;
	private double salary;
	
	//静态域初始化
	static
	{
		Random generator = new Random();
		nextId = generator.nextInt(1000);
	}
	//块初始化
	{
		id = nextId;
		nextId++;
	}
	
	public Employee(String n, double s){
		name = n;
		salary = s; 
	}
	
	public Employee( double s ){
		this( "Employee#" + nextId, s );
	}
	
	public Employee() {
			
	}
	
	public static int getNextId() {
		return nextId;
		
	}
	
	public String toString() {
		return "name: " + name + ", id: " + id + ", salary: " + salary;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值