3. 对象与类

以《Java核心技术 卷1》第10版为主,结合自身实践进行截图及细节描述

对象与类

  • 一、面向对象程序设计概述
    • 1. 类(class)
    • 2. 对象
    • 3. 识别类
    • 4. 类之间的关系
  • 二、使用预定义类
    • 1. 对象与对象变量
    • 3. 调用方法
  • 三、用户自定义类
    • 1. 简单类的定义形式
    • 2. 访问修饰符
    • 3. static和final修饰符
    • 4. 构造器
    • 5. 初始化数据域及执行顺序
    • 6. 隐/显式参数和域更改/访问器
    • 7. 方法--重载,私有,工厂,main
    • 8. 方法参数
    • 9. 对象析构与fianlize方法
  • 四、包
    • 1. 将类放入包中
    • 2. 类的导入
    • 3. 静态导入
    • 4. 包作用域
  • 五、文档注释
    • 1. 注释的插入
    • 2. 如何注释
    • 3. 注释的抽取
  • 六、类设计技巧

一、面向对象程序设计概述

  面向对象程序设计(Object Oriented Programming)(简称OOP)是当今主流的程序设计泛型。Java是完全面向对象的,所以必须熟悉OOP才能编写Java程序。

  面向对象的程序是由对象组成的,每个对象包含对用户公开的特定功能和隐藏的实现部分。程序中很多对象来自标准库,还有一些是自定义的。在OOP中,不必关心对象的具体实现,只要能够满足用户的需求即可。

  算法+数据结构=程序。传统的结构化程序设计是首先确定如何操作数据(算法),然后再决定如何组织数据(数据结构),以便于数据操作。而OOP调换了这个次序,将数据放在第一位,然后再考虑操作数据的算法。

第一部分都是理论上的东西,可以先看其他部分实践,再看理论知识

1. 类(class)

  类(class)是构造对象的模块或蓝图,由类构造对象的过程称为创建类的实例

  封装(encapsulation,也称作数据隐藏)将数据和行为组合在一个包中,并对对象的使用者隐藏了数据的实现方式。对象中的数据称为实例域,操纵数据的过程称为方法。对于每个特定的类实例(对象)都有一组特定的实例域值。这些值的集合就是这个对象的当前状态

  实现封装的关键在于绝对不能让类中的方法直接访问其他类的实例域。程序仅通过对象的方法与对象数据进行交互。这意味着一个类可以全面改变存储数据的方式,只要仍旧使用同样的方法签名,其他对象就不会知道或介意所发生的变化。

  继承(inheritance)是OOP另一准则:可以通过扩展一个类来建立另外一个新的类。扩展后的新类具有所扩展类的全部属性和方法,在新类中,只需提供适用于这个新类的新方法和数据域就可以了。【封装的知识点在第四章介绍】

2. 对象

  对象的三个主要特性:

  • 对象的行为 —— 可以对对象施加哪些操作,或可以对对象施加哪些方法?
  • 对象的状态 —— 当施加那些方法时,对象如何响应?
  • 对象标识 —— 如何辨别具有相同行为或状态的不同对象?

  同一个类的所有对象实例,由于支持相同的行为而具有家族似地相似性。对象的行为是用 可调用的方法定义的。

  每个对象都保持着描述当前特征的信息。这就是对象的状态。对象的状态可能会随着时间而发生改变,但这种改变不是自发的。对象状态的改变必须通过调用本类方法实现。(如果不是,只能说明封装性遭到破坏)

  对象的状态并不能完全描述一个对象。每个对象都有一个唯一的身份,即标识,他们永远是不同的,状态也常常存在着差异。对象的这些特性在彼此之间相互影响着。

3. 识别类

  传统的过程化程序设计,必须从顶部的main函数开始编写。而在面向对象程序设计时没有所谓的”顶部“。

  识别类(设计类)的简单规则是在分析问题的过程中寻找名词,而方法对应着动词。例如:订单处理系统中:商品,订单,地址,客户等都是名词,名词很可能成为类,而添加订单,订单被发送或取消,添加商品等都是动词,是要演变成方法的。综合来说,看个人开发经验,去区分哪些可以成为类,哪些是类中方法。

4. 类之间的关系

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

  • 依赖(uses-a)—— 一个类的方法操纵另一个类的对象。因尽可能将相互依赖的类减至最少,让类之间的耦合度最小。
  • 聚合(has a)—— 类A的对象包含类B的对象(有人喜欢将聚合称为关联)
  • 继承(is a)—— 类A扩展类B(下一章会具体讨论继承)

  用UML(Unified Modeling Langue 统一建模语言)绘制类图

UML符号

在这里插入图片描述

二、使用预定义类

  在Java中,没有类就无法做任何事情。以java.util.Date类为例,介绍如何构造对象,以及如何调用类的方法。【预定义类可使用jdk1.8帮助手册查看其属性和方法】

1. 对象与对象变量

  要想使用对象,就必须首先构造对象,并指定其初始状态。然后对对象应用方法。在Java中,普遍使用构造器(constructor)构造新实例。
  构造器是一种特殊的方法,用来构造并初始化对象。构造器的名字与类名相同。

// 构造Date对象
new Date();
	// 可以将这个对象传递给一个方法
	System.out.println(new Date());
	//也可以将一个方法应用于刚刚创建的对象
	String s = new Date().toString();
// 可以将对象存放在一个变量中,该变量称为对象变量
Date birthday = new Date();
Date anniversary = null;
anniversary.toString(); //错误使用
  • 一个对象变量并没有实际包含一个对象,而仅仅是引用一个对象
  • Date birthday = new Date(); 具体解释:new Date()构造了一个Date类型的对象,并且它的值是对新创建对象的引用,这个引用存储在变量birthday中
  • Date anniversary = null; 可以显式地将对象变量设置为null,表明这个对象变量目前没有引用任何对象。如果将一个方法应用于一个值为null的对象上,那么就会产生运行时错误。

3. 调用方法

  方法大致上分成两种:更改器方法访问器方法

  • 更改器方法:会修改对象的方法。
  • 访问器方法:只访问对象而不修改对象的方法。

  如何去调用方法呢?

  • 针对静态方法:类名.方法名(参数值);如:Math.pow(2,3);
  • 针对实例方法:对象名.方法名(参数值);如:birthday.toString();
  • 【静态方法和实例方法看下一部分】

三、用户自定义类

  在第二章中,语句都是在类中的main方法里面写。但要想创建一个完整的程序,应该将若干类组合在一起,其中只有一个类有main方法,其它类没有main方法,但是有自己的域和方法。

1. 简单类的定义形式

[public] class ClassName{
	[access modifier][static][final]type variableName;  //称为属性或域
	......
	
	[access modifier]ClassName([type parameters,...]);  //构造器
	......
	[access modifier][static][final] returnType methodName([type methodParameters,...]){ //称为方法
		...sentence...
	}	
	......
}

为了更直观的描述,举例子说明

public class Employee{
	// 属性
	private static int nextId =1;  // 静态域
	private final int nextWork;//final实例域
	public static final double PI = 3.14159265358979323846; //静态常量
	
	private String name;  //实例域
	private double salary;
	private LocalDate hireday;
	{
		...对象初始化块...
	}
	static{
		...静态初始化块...
	}
	//构造器
	public Employee(){  //无参构造器
		this.name="";
		this.salary=0.0;
	}
	public Employee(String name,double salary){ 
		this.name=name;
		this.salary=salary;
	}
	public Employee(String name,double salary,int year,int month,int day){
		this.Employee(name,salary); //调用本类另一个构造器,必须放在第一行
		this.hireday = LocalDate.of(year,month,day);
	}
	//访问器方法
	public String getName(){
		return name;
	}
	public double getSalary(){
		return salary;
	}
	public LocalDate getHireday(){
		return hireday;
	}
	//更改器方法
	public void setName(String name){
		this.name=name;
	}
	public void setSalary(double salary){
		this.salary=salary;
	}
	public void setHireday(LocalDate hireday){
		this.hireday=hireday;
	}
	
	//静态方法
	public static String staticText(){
		this.name = "en~kun"; //错误,静态方法没有this参数
		return name;   //错误,name是实例域
		return nextId+""; //正确,nextId是静态域
	}
	//私有方法
	private void privateText(){
		......
	}
}
public class EmployeeText{
	public static void main(String[] args){
		//构造对象
		Employee em =new Employee("Mark",90001996,5,24);
		//调用方法,并输出
		String sName = em.getName();
		System.out.println(sName);
		//调用静态方法
		Employee.staticText();
		//显式参数和隐式参数
		em.setName("aMark");
	}
}
  • 一个源文件(后缀是.java的文件)中只能有一个公有类(public class 修饰),但可以有任意数目的非公有类(仅class修饰,访问修饰符为默认,即什么都不写)
  • 源文件的名称与公共类的名称一致;习惯上,将每个类存在于单独的源文件中。即每个类都应该被设置为public class。(上面就是这么做的,需存放在两个源文件中)
  • 针对多个源文件,那如何进行编译呢?①使用通配符:javac Employee*.java ② javac EmployeeText.java(选择有main方法的类编译)【集成环境中编译也是选择有main方法的类执行】

2. 访问修饰符

  访问修饰符(access modifier)共有四种:private、默认(default)、protected,public。

  • 外部类只能用public或默认(default)进行修饰(即public class 或 class),不写/空白就是默认修饰符,不是得写出default。注意和内部类进行区分。【内部类在第5章有所介绍】
  • 访问修饰符是用来表示一个类,域,方法的访问权限,看下表:【关于包,子类看后面介绍】
修饰符本类同包子类其他包
public
protected
default
private

3. static和final修饰符

  ① static可以修饰 域,方法,类(静态内部类),代码块,静态导入。

  • static修饰域(称为静态域)该域在类中只存在一个,为所有对象所共享,静态域属于类,不属于任何对象。不被static修饰的域(称为实例域),该域在每个对象中都有一份拷贝。
  • static修饰方法(称为静态方法),静态方法是一种不能向对象实施操作的方法。查看上面的staticText方法,有以下规则:
    • 静态方法中是没有this参数的;
    • 静态方法不能访问实例域,但可以访问静态域;
    • 使用类名调用静态方法:Employee.staticText();但也可以通过对象调用,只不过这种方式并不推荐;
    • 不需要访问对象状态且只需访问类的静态域时,使用静态方法;
  • static修饰类,只能修饰内部类(称作静态内部类)【第5章会有介绍】
  • static修饰代码块,后面部分介绍。
  • 静态导入,第二章接触过import static java.lang.Math.*适用于类中全是静态属性和方法的情况。

  ② final可以修饰 变量,方法,类。

  • final修饰变量(即表示final可修饰域,也可修饰方法中定义的变量),值不可被修改。
    • final修饰符大多应用于基本类型域,或不可变类的域(如String类,类中方法不会改变其对象);
    • 当final修饰符应用于可变的类(如:StringBuilder),只是表示对象引用不可变(即不可将其他对象变量引用赋给final修饰的变量),但对象的值是可以改变的;
  • final修饰方法,表示不可被重写【第四章会有介绍】
  • final修饰类,表示不可被继承【第四章会有介绍】

  ③ static final修饰变量:可设访问修饰符为public(如上PI域)。因为并没有什么影响:不能改变其值,为类所属。

4. 构造器

① 构造器基本规则

  • 构造器与类同名
  • 每个类可以有一个以上的构造器
  • 构造器可以有0个,1个或多个参数(方法参数)
  • 构造器没有返回值
  • 构造器总是伴随new操作一起调用
  • 若一个类中没有写构造器,那么系统会给其分配一个默认的无参构造器,将所有的实例域设置为默认值(数值为0,布尔值为false,对象应用为null)。有写的话,就不分配了。

② 调用另一个构造器

  若构造器的第一个语句形如this(…),这个构造器将调用同一个类的另一个构造器(如上代码中第三个构造器)。需要注意的是:this(…) 必须放在第一行。

5. 初始化数据域及执行顺序

  初始化数据域有三种方式:

  1. 在构造器中设置值。(见上)
  2. 在声明中赋值。其实若域没有被设置值,系统会自动给域赋默认值:数值为0,布尔值为false,对象应用为null。注意将域和局部变量(方法中定义的变量)进行区分,局部变量不会有赋初值这个行为。
  3. 初始化块(也称代码块)。初始化块分静态初始化块和对象初始化块。一个类中可以包含多个代码块。代码块其实是一体的,即不可在不同代码块中声明同名的变量。

执行顺序

   在类第一次被加载时,会将所有静态的变量,方法,静态初始化块执行。执行顺序按照其在类中定义的顺序。因此建议将代码块放在域定义之后,不然可能会有非法前向引用的错误。

  在构建对象时,会将实例域,对象代码块,构造器方法 执行。实例域与对象代码块顺序执行,最后执行构造器方法。

6. 隐/显式参数和域更改/访问器

① 隐/显式参数

  • 隐式参数:出现在方法名前的类对象(em),特别地:this关键字
  • 显式参数:位于方法名后面括号中的数值(“aMark”)

  在方法中,关键词this表示隐式参数。常用于构造器方法中对实例域赋值。(this.name=name;)this表示本对象。

① 域更改/访问器

  查看Employee类中的域,发现实例域都是private修饰的。因为我们并不允许对象的域值可以被肆意更改或获取,所以选择封装一个域【封装知识下一章介绍】。如何封装呢?

  • 一个私有的数据域(如:name,salary,hireday)
  • 一个公有的域访问器(getName,getSalary,getHireday方法)
  • 一个公有的域更改器(setName,setSalary,setHireday方法)

在编写域访问器时要特别注意:

  不要编写返回 引用可变对象 的访问器方法。比如一个访问器返回了Date类对象,Date类中有setTime方法,它是在原对象身上修改时间。换句话说:通过setTime,对em对象的hireDay属性做了修改。这破坏了封装性。
在这里插入图片描述
  所以如果需要返回一个可变对象的引用,应该首先对它进行克隆。即:return (Date)hireDay.clone()

7. 方法–重载,私有,工厂,main

① 重载

  之前看到过构造器可以有多个,这种特征叫重载。编译器通过用各个方法给出的参数类型与特定方法调用所使用的值类型进行匹配来挑选出相应的方法。

  Java允许重载任何方法,而不只是构造器方法。重载的要求是方法签名不同。方法签名:方法名和参数类型。注意:返回类型不是方法签名的一部分,所以不能有两个名字相同,参数类型也相同却返回不同类型值的方法。

举例:

indexOf(int)
indexOf(int,int)
indexOf(String)
indexOf(String,int)

  Java中,所有的方法都必须在类的内部定义,但这并不表示它们是内联方法。是否将某个方法设置为内联方法是Java虚拟机的任务。即时编译器会监视调用那些简洁、经常被调用,没有被重载以及可优化的方法。

② 私有方法

  在编写一个类时,由于公有数据非常危险,所以将所有的数据域都设置为私有的。那私有方法为什么被设计呢?有时,希望将一个计算代码划分成若干个独立的辅助方法,这些辅助方法要么与当前的实现机制非常紧密,要么需要特别的协议以及调用次序,故不应该成为公有接口的一部分。

  怎么实现?方法public 改为private即可。

③ 工厂方法

  类似LocalDate类,使用静态工厂方法来构造对象。

  操作步骤:类中不写构造器或者private修饰构造器;写一个静态方法,返回一个对象。如下:

public static Employee getNewEmloyee(...){
	......
	return new Employee(...);
}

  为什么要用工厂方法取代构造器呢?

  1. 无法命名构造器。构造器的名字必须与类名相同。有时:一个类中有两种表现形式的实例:比如货币实例或百分比实例。希望在构造对象时就有所区分。
  2. 当使用构造器时,无法改变所构造的对象类型。但有时又需要返回其子类对象。

④ main方法

  main方法不对任何对象进行操作。事实上,在启动程序时还没有任何一个对象。静态main方法将执行并创建程序所需要的对象。

  每个类中都可以有一个main方法,此举常用于对类进行单元测试。

8. 方法参数

  参数名,变量名,方法名都是一样的命名规范:小驼峰(首字母小写,其他单词首字母大写,允许字母和数字,长度无限制)。

  在参数传递过程中,有两种方式。一种按值调用(也叫:按值传递):表示方法接受的是调用者提供的值;另一种按引用调用(也叫:引用传递):表示方法接受的是调用者提供的变量地址。两者的区别是:方法可以修改引用调用所对应的变量值,但不能修改值调用所对应的变量值。

  Java中只有按值调用。也就是说:方法得到的是所有参数值的一个拷贝。方法参数有两种类型:基本数据类型和引用类型。下面举例说这两种的区别。

// 基本数据类型
public static void tripleValue(int x){    //定义一个方法,将x*3。
	x *=3;
} 
tripleValue(10); //调用该方法

// 引用类型
public static void tripleValue(Employee x){ //定义一个方法,将Employee x薪水涨3倍。
	x.setSalary(3*x.getSalary());
}
Employee harry = new Employee("harry",4000);
tripleValue(harry); //调用该方法
①基本数据类型按值传递

在这里插入图片描述

②引用类型按值传递

在这里插入图片描述
  根据上面两个图发现:

  • 一个方法不可能修改一个基本数据类型的参数(即数值型或布尔型)
  • 一个方法可以修改一个对象参数的状态
  • 一个方法不能让对象参数引用一个新对象

9. 对象析构与fianlize方法

  析构器方法(C++有),存放一些当对象不再使用时需要执行的清理代码。但java有自动的垃圾回收器,所以不需要人工回收内存,同样Java也不需要析构器。

  Java中可以为任何一个类添加finalize方法。finalize方法将在垃圾回收器清楚对象之前调用。实际应用中,不要使用finalize方法来回收短缺的资源,因为并不知道这方法什么时间调用。

  如果某个资源需要在使用完毕之后立刻被关闭,应用close() 方法来完成相应的清理操作。

四、包

  Java使用包(package)将类组织起来。借助于包可以方便地组织自己的代码,并将自己的代码与别人提供的代码库分开管理。所有标准的Java包都处于java和javax包层次中。

  使用包的主要原因时确保类名的唯一性。比如:两个程序员编写了同名的类,只要处于不同的包,就不会起冲突。从编译器角度看:嵌套的包之间没有任何关系,例如:java.util包与java.util.jar包之间毫无关系。

  包名命名规范:全小写,以 . 分隔;Sum公司建议将公司的因特网域名以逆序的形式作为报名。例:百度网(baidu.com),所以包名:com.baidu

1. 将类放入包中

  将包的名字放在源文件的开头。

package com.csdn.enkun
public class Employee{
	......
}

注意事项

  • 如果没有在源文件中放置package语句,这个源文件中的类就被放置在一个默认包(default package)中
  • 包名与目录结构相同。如包名com.csdn.enkun,那么目录结构:com/csdn/enkun/Employee.java

2. 类的导入

  一个类可以使用所属包中的所有类,以及其他包中的公有类。有两种方式访问另一个包中的公有类。

  1. 类名之前添加完整的包名
java.time.LocalDate today = java.time.LocalDate.now();
  1. 使用import语句,可以导入一个特定的类或者整个包。import语句在源文件的顶部(package语句后面)(推荐使用
import java.time.*;  //导入整个包
import java.time.LocalDate;  //导入特定的类 (推荐)
LocalDate today = LocalDate.now(); //此时调用方法时不用写完整包名

注意事项

  • 只能使用星号(*)导入一个包,不能使用 import java.* 导入以java为前缀的所有包
  • 有时会遇到命名冲突的情况:导入的两个包中有同名的类,在使用时,需在类名前加上完整的包名
  • 在包中定位类是编译器的工作。类文件中字节码使用完整的包名引用其他的类

3. 静态导入

  import语句不仅可以导入类,还增加了导入静态方法和静态域的功能。

  1. 导入某类的静态方法和静态域,使用时不必加类名前缀
import static java.lang.System.*;
out.println("GoodBye,en~kun"); //原型:System.out.println("GoodBye,en~kun");
  1. 导入特定的方法或域
import static java.lang.System.out;

4. 包作用域

  在看这块之前,请先温习一下:三、2访问修饰符。发现:包中的类可以访问本包中默认修饰符修饰的类,变量,方法。在Java程序设计初期,其实有些类(如:Window)的属性并没有被private修饰。那如果写个类,将此类放在指定的包中(如java.awt),利用包的可见性,就可以对那些类中的属性进行一些修改。

  为了解决上面的问题,从1.2开始,类加载器明确禁止加载用户自定义的,包名以“java”开始的类,这是一种保护。当然,对于用户来说,可通过包密封(package sealing)机制实现这一目的:禁止其他用户将类向我创建的包中添加。【包密封机制第8章会介绍】

五、文档注释

  在第二章中提过文档注释的使用:/** … */。它其实叫javadoc,可以将源文件生成一个HTML文档。如下图:
在这里插入图片描述
在这里插入图片描述

1. 注释的插入

 javadoc程序从下面特性中抽取信息,注释也应放置在所描述特性的前面。

  1. 公有类和接口
  2. 公有的和受保护的构造器和方法
  3. 公有的和受保护的域

用法举例

/**
	自由格式文本:javadoc会自动将这些文本抽取,如上面ceshi方法下面的拼音注释。
	标记:由@开始,例@author,@param
*/
/**
 *  这种形态也是可以的,但没必要每行都加星号。但是大部分IDE,都自动添加星号,并排列
 *
*/

注意:标记和自由格式文本的顺序不能变,标记在下,自由格式文本在上。

自由格式文本

  自由格式文本,可以使用HTML修饰符。强调:<em></em>;着重强调:<strong></strong>;图像:<img ...>等。不要使用<h1><hr>,它们会与文档的格式造成冲突。键入等宽代码:{@code......}

   若文档中有用到其它文件的链接。例如图像文件,就将这些文件放到子目录doc-files中。使用时:<img src=“doc-files/uml.png” alt="UML diagram">

2. 如何注释

特性描述
类注释类注释必须放在import语句之后,类定义之前
方法注释必须放在所描述方法之前
@param:为参数部分添加一个条目,可以使用HTML标记,可以跨越多行
@return:添加返回部分,可跨越多行,可使用HTML标记
@throw:表示当前方法有可能抛出异常
域注释只对公有域(静态常量)建立文档
通用注释@author 作者姓名,可以有多个@author标记,每个标记对应一个作者,用在类文档中
@version 文本,对当前版本的描述,多用在类文档中
@since 文本,表示从哪个版本开始有了,例:@since version 1.7.1
@deprecated 文本 对类,方法或变量添加一个不再使用的注释
@see 后面可以跟类名#方法名,也可以跟a标签,也可以跟文本。会放到see also位置
包注释需要在每个包目录中提供一个单独的文件。
可以是package.html,<body>...</body>之间所有的文本会被提取出来。
也可以是package-info.java,将/** … … */的内容提取出来 ,该文件不应包含代码和注释
概述注释为所有的源文件提供一个概述性的注释,注释放在overview.html 文件中
该文件位于包含所有源文件的父目录中。<body>...</body>之间的文本会被提取

举例:

package com.csdn.enkun
/**
	类注释
*/
public class JavadocSee{

	/**
		域注释
	*/
	public static final double PI = 3.1415926;

	/**
		方法注释。自由格式文本位置。在javadoc生成的HTML中,方法和说明,首页只显式一行。
			后面几行在点击方法之后才会显式。如上图。
		@param em 雇员属性
		@param name 名字属性  -- 有几个参数就需要几个@param进行参数指定
		@return 有返回类型,才可使用此标记
		@throws IllegalArgumentException --@throws标记和@param一样,后面先跟具体名称再进行描述,有几个异常使用几个@throws标记
			@throws 只是表示有可能抛出异常,所以即使方法没有显式写throws,也可添加此标记
	*/
	public static int setName(Employee em,String name)[throws IllegalArgumentException]{
		...上面的[...]表示可有可无,不会对@throws标记产生影响...
	}

	/**
		@see 可用在所有文档注释中,会放在see also(另请参考)位置,有3种用途
		@see package.class#feature label 例:@see com.csdn.enkun.Employee#getName()
		@see <a href="">label</a>  例:@see <a href="www.baidu.com">百度网</a>
		@see “text” 例:@see “java核心卷I第四章”
	*/
	
}

3. 注释的抽取

  通过上述步骤,应该在java源文件中添加了文档注释,接下来就是利用javadoc命令将其转化为html。(下面仅从cmd中执行,集成环境请看其它相关教程进行注释抽取)

  1. 切换目录。切换到想要生成文档的源文件目录或者包的顶层目录(之前的例子是com)
  2. 运行命令(docDirectory 是指生成html的目录位置)
javadoc -d docDirectory nameOfPackage #生成指定包的文档注释
javadoc -d docDirectory nameOfPackage1 nameOfPackage1... #生成多个包的文档注释
javadoc -d docDirectory *.java #若文件在默认包中,生成目录下所有java文件的注释

六、类设计技巧

设计技巧解释
一定要保证数据私有历史经验:数据的表现形式很可能发生改变,但使用方式却不会经常发生改变。当数据保持私有,存在域更改/访问器,表现形式的改变并不会对使用者造成影响。
一定要对数据初始化Java不会对局部变量进行初始化,但会对域进行初始化,但请不要依赖系统的默认值
不要在类中使用过多的基本类型用其他的类代替多个相关的基本类型的使用。简单来说就是扩大聚合
不是所有的域都需要独立的域访问器和域更改器在一些类中,常常包含一些不希望别人获得或设置的实例域
将职责过多的类进行分解每个人关于此点看法不同,但是如果明显地可以将一个复杂地类分解成两个l更为简单的类,就应该将其分解
类名和方法名要体现他们的职责类名命名的良好习惯是采用一个名词、前面有形容词修饰的名词或动名词修饰名词。对于方法来说:访问器用小写get开头,更改器用小写set开头
优先使用不可变的类如果多个线程试图同时更新一个可变对象,就会发生并发更改,结果不可预料。但若类是不可变的,就可以安全地在多个线程间共享对象

热门文章

编程学习 ·

java后端重点

java基础,设计模式,jvm原理,spring+springmvc原理及源码,linux,mysql事务隔离与锁机制,mongodb,http/tcp,多线程,分布式架构(dubbo,dubbox,spring cloud),弹性计算架构,微服务架构(springboot+zookeeper+docker+jenkins),java性能优化,以及相关的项目管理等…
编程学习 ·

MySQL 简洁速查手册

MySQL 速查手册 文章目录MySQL 速查手册0. 前言1. 开启/关闭数据库2. 数据库操作3. 数据表操作4. 字段操作5. 数据操作6. 运算符7. 高级查询(group by、having、order by、limit)8. 高级插入9. 高级删除10. 高级更新11. 联合查询12. 连接查询12.1 左外连接12.2 右外连接13. 子查…
编程学习 ·

STM32开放式开发环境:释放创造力

市场上涌现各种价格亲民的经济型微控制器,助力新一代开发者创造令人兴奋的新型嵌入式应用。如今的开发工具非常好用,软硬件均呈现模块化趋势,插接安装简单容易,使得产品设计评估和原型开发周期大幅缩短。STM32开放式开发环境是业内独一无二的软硬件开发平台,堆叠式插接电路…
编程学习 ·

Vue&Element

Vue&Element Vue 快速入门 Vue 介绍Vue 是一套构建用户界面的渐进式前端框架。 只关注视图层,并且非常容易学习,还可以很方便的与其它库或已有项目整合。 通过尽可能简单的 API 来实现响应数据的绑定和组合的视图组件。 特点 易用:在有 HTML CSS JavaScript 的基础上,快…
编程学习 ·

挂牌一年,关于 5G 的 9 个变化

简介:2019 年 6 月 6 日的一张新闻图片瞬间刷遍全网,意味着中国正式进入 5G 时代,2019 年也被业界称为 5G 商用元年。转眼间一年过去,这个不断被提及的 5G 新星发展到了什么程度呢,让我们再来回顾和展望一下。3GPP 标准进展移动通讯网络作为全球的基础设施,标准化是基础,…
编程学习 ·

springboot 整合xcf 发布 webservice

Spring Boot集成webService在pom添加依赖<!--WerbService CXF依赖 start--> <dependency><groupId>org.apache.cxf</groupId><artifactId>cxf-rt-frontend-jaxws</artifactId> </dependency> <dependency><groupId>org.…
编程学习 ·

navigation笔记

react native存在的问题 vscode怎样打断点 _onPressButton()为什么以下划线命名 setState用法 render()用法eslint报错 不懂的地方:不懂怎么调试 不懂apk入库yarn start报错不知道怎么去解决 1 怎样让调试栏目处于最顶部 2 怎样快速找到问题的地方 3 怎么快速打断点类为什么前…
编程学习 ·

Flink原理与实现:Flink中的状态管理,keygroup,namespace

namespace维护每个subtask的状态上面Flink原理与实现的文章中,有引用word count的例子,但是都没有包含状态管理。也就是说,如果一个task在处理过程中挂掉了,那么它在内存中的状态都会丢失,所有的数据都需要重新计算。从容错和消息处理的语义上(at least once, exactly onc…
编程学习 ·

快速排序进阶

三月不练手生。翻出了以前写的快速排序、单链表快排和scala快排。老老实实写把基础版写对就足够。 本文代码均经过测试。 1,快速排序的C++写法: #include <iostream> #include <vector> #include <algorithm>using namespace std;int getPartition(int arr…
编程学习 ·

2. judgeSquareSum

忘记是自然选择,重要的是抽取学习方法双指针 --判断某一非负整数是否是两数平方和(easy) leecode输入:5 输出:true 5=1^2 + 2^2 思路:等于从一个有序数组找两个数平方和为target,注意的是最大值肯定小于Math.sqrt(target)public boolean judgeSquareSum(int c) {if (c < 0)…
编程学习 ·

inotify 安装配合rsync

inotify是细粒度的实时监控结合rsync备份 inotify安装 yum install inotify-tools [root@nfs01 ~]# cd /proc/sys/fs/inotify/ [root@nfs01 inotify]# ls max_queued_events max_user_instances max_user_watches 最大可容纳事件(相当于一个池) 每个用户可以运行的进程…
编程学习 ·

Java-WrapperClass及其转化

java里的变量分为primitive type和reference type两种。primitive type是int, char, double啥的,reference type(Wrapper Class)就是Integer, String这些。 我一直对reference type互相转化有点记不住,看了几个视频学习了一下。发现是因为对reference type(Wrapper Class)原理…
编程学习 ·

linux笔记(三)Linux的基本命令

1 cd 切换目录2 ls 查看目录下的内容3 mkdir 创建文件夹4 touch 创建文件5 cp 复制 文件和文件夹6 mv 剪切移动 文件夹和文件7 rm 删除1 cd 切换目录带/ 绝对路径 ./ ../ ../../ 相对路径cd - 切换到上次所在的目录cd ~ 回到当前用户的家目录 /root /homecd - 切…
编程学习 ·

Java正确URL解码方式:URLDecoder.decode

Java调用 URLDecoder.decode(data, “UTF-8”); 抛出的异常,其主要原因是% 在URL中是特殊字符,需要特殊转义一下:url = url.replaceAll("%(?![0-9a-fA-F]{2})", “%25”); String urlStr = URLDecoder.decode(url, “UTF-8”);其他特殊字符以及对应的替代:
编程学习 ·

169. 多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。 你可以假设数组是非空的,并且给定的数组总是存在多数元素。 示例 1: 输入: [3,2,3] 输出: 3 示例 2: 输入: [2,2,1,1,1,2,2] 输出: 2 class Solution { public:int majori…
编程学习 ·

java 中常用框架、intell idea的使用、爬虫系统

***intell idea的使用设置mavende本地仓库:file-》settings-〉build-》build tools-〉maven-》配置maven的环境,maven home directory,user setting files,local repository***java 中常用框架**mycat:数据库操作;https://www.cnblogs.com/fyy-hhzzj/p/9044775.htmlmycat分布式…
编程学习 ·

AT命令总结

一、一般命令1、AT+CGMI: 请求得到移动设备生产厂商的标识。2、AT+CGMM: 请求得到移动设备模块的标识。3、AT+CGMR: 请求得到改订的系统版本,修改级别和日期,以及其他相关内容。4、AT+CGSN: 得到GSM移动设备的唯一标识,比如IMEI(国际移动设备标识)序列号。5、AT+CSCS …