Java基础知识查漏补缺(Java核心技术)----对象和类

疫情期间不能出门好无聊,天天刷抖音,刷微博,微博上骂白痴,刷知乎,刷的我都不知道天地为何物了,另外我觉得我的作息事件都被搞反了,每天下午才起来。啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊,我新时代的五好青年怎么能这样。要假装学习那么几分钟,来安慰安慰自己。

知识点1: 类之间的关系:

  • 依赖关系(dependence):
    依赖(dependence),即“uses-a”关系,是一种最明显的、最常见的关系。例 如,Order类使用Account类是因为Order对象需要访问Account对象查看信用状 态。但是Item类不依赖于Account类,这是因为Item对象与客户账户无关。因此, 如果一个类的方法操纵另一个类的对象,我们就说一个类依赖于另一个类。
    应该尽可能地将相互依赖的类减至最少。如果类A不知道B的存在,它就不会关心B的 任何改变(这意味着B的改变不会导致A产生任何bug)。用软件工程的术语来说,就 是让类之间的耦合度最小。

  • 聚合关系(aggregation):
    即“has-a”关系,是一种具体且易于理解的关系。例如, 一个Order对象包含一些Item对象。聚合关系意味着类A的对象包含类B的对象。也有程序员称为关联关系

  • 继承关系(inheritance)
    即“is-a”关系,是一种用于表示特殊与一般关系的。例 如,Rush Order类由Order类继承而来。在具有特殊性的RushOrder类中包含了一 些用于优先处理的特殊方法,以及一个计算运费的不同方法;而其他的方法,如添 加商品、生成账单等都是从Order类继承来的。一般而言,如果类A扩展类B,类A不 但包含从类B继承的方法,还会拥有一些额外的功能。

很多程序员采用UML(Unified Modeling Language,统一建模语言)绘制类图, 用来描述类之间的关系。下图就是这样一个例子。类用矩形表示,类之间的关系用 带有各种修饰的箭头表示。下表给出了UML中最常见的箭头样式。
类图:
类图
表达类关系的UML符号
在这里插入图片描述

知识点2

在一个源文件中,只能有一个公有类,但可以有任意数目的非公有类。并且文件名必须与public类的名字相匹配。

知识点3 final关键字

  • final关键字修饰类
    当用final去修饰一个类的时候,表示这个类不能被继承。
    注意
    a. 被final修饰的类,final类中的成员变量可以根据自己的实际需要设计为fianl。
    b. final类中的成员方法都会被隐式的指定为final方法。
    说明
    在自己设计一个类的时候,要想好这个类将来是否会被继承,如果可以被继承,则该类不能使用fianl修饰,在这里呢,一般来说工具类我们往往都会设计成为一个fianl类。在JDK中,被设计为final类的有String、System等。

  • final关键字修饰方法
    被final修饰的方法不能被重写
    注意
    a. 一个类的private方法会隐式的被指定为final方法。
    b. 如果父类中有final修饰的方法,那么子类不能去重写该方法。

  • final关键字修饰成员变量
    a. 必须要赋初始值,而且是只能初始化一次。
    b. 被fianl修饰的成员变量赋值,有两种方式:1、直接赋值 2、全部在构造方法中赋初值。
    c. 如果修饰的成员变量是基本类型,则表示这个变量的值不能改变。
    d. 如果修饰的成员变量是一个引用类型,则是说这个引用的地址的值不能修改,但是这个引用所指向的对象里面的内容还是可以改变的。

知识点4:工厂方法

静态方法的一种常见用途就是工厂方法
在这里插入图片描述
如上图所示,NumberFormat类如下使用工厂方法生成不同风格的格式化对象。

问题来了?为什么NumberFormat不使用构造器来创建不同风格的对象呢。

主要是由于工厂方法有两个:
优点

  1. 用户只需要关心所需产品对应的工厂,无需关心创建的细节。
  2. 加入新产品符合开闭原则,提高可扩展性。

缺点

  1. 类的个数容易过多,增加复杂度。
  2. 增加了系统的抽象性和理解难度。

知识点5:main方法

  • main方法也是一个静态方法。
  • 每一个类可以有一个main方法。这是一个常用于对类进行单元测试的技巧。

知识点6:

Java程序设计语言总是采用按值调用。也就是说,方法得到的是所有参数值的一个 拷贝,特别是,方法不能修改传递给它的任何参数变量的内容。

知识点7:方法签名

方法签名包括两个部分 (方法名+参数)。只有方法名和参数都一致才叫做一个同一个签名。
方法的签名在重载方面常见:
Java允许重载任何方法,而不只是构造器方法。因此,要完整地描述一 个方法,需要指出方法名以及参数类型。这叫做方法的签名(signature)。例 如,String类有4个称为indexOf的公有方法。它们的签名是
在这里插入图片描述
返回类型不是方法签名的一部分。也就是说,不能有两个名字相同、参数类型也相 同却返回不同类型值的方法。

知识点8:默认构造函数

如果在构造器中没有显式地给域赋予初值,那么就会被自动地赋为默认值:数值为 0、布尔值为false、对象引用为null。

知识点9:调用另一个方法的构造器

关键字this引用方法的隐式参数。然而,这个关键字还有另外一个含义。
如果构造器的第一个语句形如this(…),这个构造器将调用同一个类的另一个 构造器。下面是一个典型的例子:
在这里插入图片描述
当调用new Employee(60000)时,Employee(double)构造器将调用 Employee(String,double)构造器。
采用这种方式使用this关键字非常有用,这样对公共的构造器代码部分只编写一次即可。

知识点10:初始化块

参考文章(这个文章写的非常好,我就拿过来在这里给大家做个参照):https://blog.csdn.net/china_songlei/article/details/79696583

初始化块(initialization block)。在一 个类的声明中,可以包含多个代码块。只要构造类的对象,这些块就会被执行。例如:

在这里插入图片描述
在这个示例中,无论使用哪个构造器构造对象,id域都在对象初始化块中被初始 化。首先运行初始化块,然后才运行构造器的主体部分。
这种机制不是必需的,也不常见。通常会直接将初始化代码放在构造器中。

附加解释:
初始化块分为静态初始化块和普通初始化块。其好处是减少多个构造器内重用的代码;

  • 1 .调用的时机不一样:普通初始化块:创建对象时隐式调用静态初始化块:类加载时隐式调用
    看下面的代码
public class TestInit1 {
    
    
	
	public static void main(String[] args) {
    
    
		System.out.println((int)(Math.random()*40+1));
		System.out.println(InitDemo1.a);//加载类
		new InitDemo1();
	}
}
class InitDemo1{
    
    
	static int a =100;
	{
    
    
		System.out.println("我是普通初始化块");
	}
	static{
    
    
		System.out.println("我是静态初始化块");
	}
}

运行结果为
在这里插入图片描述

  • 2.静态初始化块只调用一次(类加载时),而普通初始化块可以调用多次,随着对象的创建而加载
public class TestInit3 {
    
    
	public static void main(String[] args) {
    
    
		new InitDemo3();//加载+创建对象
	}
}
class InitDemo3{
    
    
	{
    
    
		System.out.println("我是普通初始化块1");
	}
	static{
    
    
		System.out.println("我是静态初始化块1");
	}
	{
    
    
		System.out.println("我是普通初始化块2");
	}
	{
    
    
		System.out.println("我是普通初始化块3");
	}
	static{
    
    
		System.out.println("我是静态初始化块2");
	}
	static{
    
    
		System.out.println("我是静态初始化块3");
	}
}
  • 3.一个类中可以有多个静态初始化块和多个普通初始化块;静态初始化块的执行要早于普通初始化块;同一个类型的初始化块的执行顺序取决于定义的先后顺序!
public class TestInit3 {
    
    
	public static void main(String[] args) {
    
    
		new InitDemo3();//加载+创建对象
	}
}
class InitDemo3{
    
    
	{
    
    
		System.out.println("我是普通初始化块1");
	}
	static{
    
    
		System.out.println("我是静态初始化块1");
	}
	{
    
    
		System.out.println("我是普通初始化块2");
	}
	{
    
    
		System.out.println("我是普通初始化块3");
	}
	static{
    
    
		System.out.println("我是静态初始化块2");
	}
	static{
    
    
		System.out.println("我是静态初始化块3");
	}
}

运行结果:
在这里插入图片描述

  • 4.在一个类中如果有多个不同的初始化块,初始化属性,构造器,执行顺序是:
    静态初始化块|静态属性初始化 > 普通初始化块|普通属性初始化 > 构造器
public class TestInit4 {
    
    
	public static void main(String[] args) {
    
    
		InitDemo4 id = new InitDemo4();
	}
}
class InitDemo4{
    
    
	public InitDemo4(){
    
    
		System.out.println("我是构造器");
	}
	String a=msg("普通属性初始化1");
	public static String msg(String info){
    
    
		System.out.println(info);
		return info;
	}
	static{
    
    
		System.out.println("静态初始化块2");
	}
	static String b=msg("静态属性初始化1");
	{
    
    
		System.out.println("我是普通初始化块1");
	}
	String c=msg("普通属性初始化2");
	{
    
    
		System.out.println("我是普通初始化块2");
	}
	static String d=msg("静态属性初始化2");
	static{
    
    
		System.out.println("静态初始化块1");
	}
}

运行结果:
在这里插入图片描述

  • 5.在父子类中,执行顺序是:

爷爷类的静态初始化块|静态属性初始化>
父类静态初始化块|静态属性初始化>

子类静态初始化块|静态属性初始化>

爷爷类普通初始化块|普通属性初始化>构造器>
父类普通初始化块|普通属性初始化>构造器>
子类普通初始化块|普通属性初始化>构造器

public class TestInit5 {
    
    
	public static void main(String[] args) {
    
    
		InitDemo5 id = new InitDemo5();
	}
}
 
class Grand {
    
    
	public Grand() {
    
    
		System.out.println("我是爷爷类的构造器");
	}
 
	String a = fun("爷爷类的普通属性初始化");
 
	public static String fun(String info) {
    
    
		System.out.println(info);
		return info;
	}
 
	static {
    
    
		System.out.println("爷爷类的静态代码块");
	}
	{
    
    
		System.out.println("爷爷类的普通代码块");
	}
	static String d = fun("爷爷类的静态属性初始化");
}
 
class Father extends Grand {
    
    
	public Father() {
    
    
		System.out.println("我是爷爷类的构造器");
		System.out.println("我是父类的构造器");
	}
 
	String a = method("父类的普通属性初始化");
 
	public static String method(String info) {
    
    
		System.out.println(info);
		return info;
	}
 
	static {
    
    
		System.out.println("父类的静态代码块");
	}
	{
    
    
		System.out.println("父类的普通代码块");
	}
	static String d = method("父类的静态属性初始化");
}
 
class InitDemo5 extends Father {
    
    
	public InitDemo5() {
    
    
		System.out.println("我是子类的构造器");
	}
 
	String a = msg("子类的普通属性初始化");
 
	public static String msg(String info) {
    
    
		System.out.println(info);
		return info;
	}
 
	static {
    
    
		System.out.println("子类的静态代码块");
	}
	{
    
    
		System.out.println("子类的普通代码块");
	}
	static String d = msg("子类的静态属性初始化");
}

运行结果为 :
在这里插入图片描述

  • 6.静态初始化块中遵循静态成员的特点,只能直接访问静态成员!也就是在静态初始化块只能修改静态成员。
class A{
    
    
	final int x;
	final static  int y;
	public A(){
    
    
		y=10;
		x=100;//×
	}
	{
    
    
		x=100;
		y=10;//×
	}
}

普通初始化块只能初始化普通的变量,普通的构造器也只能初始化普通的变量。

知识点11:包

为了更好地组织类,Java 提供了包机制,用于区别类名的命名空间。

包的作用

  • 1、把功能相似或相关的类或接口组织在同一个包中,方便类的查找和使用。

  • 2、如同文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同类名的类时,应该加上包名加以区别。因此,包可以避免名字冲突。

  • 3、包也限定了访问权限,拥有包访问权限的类才能访问某个包中的类。

Java 使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。

一个包(package)可以定义为一组相互联系的类型(类、接口、枚举和注释),为这些类型提供访问保护和命名空间管理的功能。

以下是一些 Java 中的包:

  • 1.java.lang-打包基础的类
  • 2.java.io-包含输入输出功能的函数

创建包
创建包的时候,你需要为这个包取一个合适的名字。之后,如果其他的一个源文件包含了这个包提供的类、接口、枚举或者注释类型的时候,都必须将这个包的声明放在这个源文件的开头。

包声明应该在源文件的第一行,每个源文件只能有一个包声明,这个文件中的每个类型都应用于它。

如果一个源文件中没有使用包声明,那么其中的类,函数,枚举,注释等将被放在一个无名的包(unnamed package)中。

让我们来看一个例子,这个例子创建了一个叫做animals的包。通常使用小写的字母来命名避免与类、接口名字的冲突。
在 animals 包中加入一个接口(interface):

/* 文件名: Animal.java */
package animals;
 
interface Animal {
    
    
   public void eat();
   public void travel();
}

接下来,在同一个包中加入该接口的实现:

package animals;
 
/* 文件名 : MammalInt.java */
public class MammalInt implements Animal{
    
    
 
   public void eat(){
    
    
      System.out.println("Mammal eats");
   }
 
   public void travel(){
    
    
      System.out.println("Mammal travels");
   } 
 
   public int noOfLegs(){
    
    
      return 0;
   }
 
   public static void main(String args[]){
    
    
      MammalInt m = new MammalInt();
      m.eat();
      m.travel();
   }
}

然后,编译这两个文件,并把他们放在一个叫做animals的子目录中。 用下面的命令来运行:

$ mkdir animals
$ cp Animal.class  MammalInt.class animals
$ java animals/MammalInt
Mammal eats
Mammal travel

import 关键字
为了能够使用某一个包的成员,我们需要在 Java 程序中明确导入该包。使用 “import” 语句可完成此功能。

在 java 源文件中 import 语句应位于 package 语句之后,所有类的定义之前,可以没有,也可以有多条,其语法格式为:

import package1[.package2…].(classname|*);

如果在一个包中,一个类想要使用本包中的另一个类,那么该包名可以省略。

假如payroll 包已经包含了 Employee 类,但是 Boss 类不在 payroll 包中又会怎样?Boss 类必须使用下面几种方法之一来引用payroll包中的Employee类。

方法1:使用类的全名描述

payroll.Employee

方法2:用 import 关键字引入,使用通配符 “*”

import payroll*;

方法3:使用import类导入指定类

import payroll.Employee

类文件中可以包含任意数量的 import 声明。import 声明必须在包声明之后,类声明之前。

知识点12:类设计技巧

  • 1.一定要保证数据私有
    这是最重要的;绝对不要破坏封装性。有时候,需要编写一个访问器方法或更改器 方法,但是最好还是保持实例域的私有性。很多惨痛的经验告诉我们,数据的表示 形式很可能会改变,但它们的使用方式却不会经常发生变化。当数据保持私有时, 它们的表示形式的变化不会对类的使用者产生影响,即使出现bug也易于检测。

  • 2.一定要对数据初始化
    Java不对局部变量进行初始化,但是会对对象的实例域进行初始化。最好不要依赖 于系统的默认值,而是应该显式地初始化所有的数据,具体的初始化方式可以是提 供默认值,也可以是在所有构造器中设置默认值。

  • 3.不要在类中使用过多的基本类型
    就是说,用其他的类代替多个相关的基本类型的使用。这样会使类更加易于理解且
    易于修改。例如,用一个称为Address的新的类替换一个Customer类中以下的实例域:
    在这里插入图片描述
    这样,可以很容易处理地址的变化,例如,需要增加对国际地址的处理

  • 4.不是所有的域都需要独立的域访问器和域更改器
    或许,需要获得或设置雇员的薪金。而一旦构造了雇员对象,就应该禁止更改雇用 日期,并且在对象中,常常包含一些不希望别人获得或设置的实例域,例如,在 Address类中,存放州缩写的数组。

  • 5.将职责过多的类进行分解
    这样说似乎有点含糊不清,究竟多少算是“过多”?每个人的看法不同。但是,如 果明显地可以将一个复杂的类分解成两个更为简单的类,就应该将其分解(但另一 方面,也不要走极端。设计10个类,每个类只有一个方法,显然有些矫枉过正 了)。

  • 6.类名和方法名要能够体现它们的职责
    与变量应该有一个能够反映其含义的名字一样,类也应该如此(在标准类库中,也 存在着一些含义不明确的例子,如:Date类实际上是一个用于描述时间的类)。
    命名类名的良好习惯是采用一个名词(Order)、前面有形容词修饰的名词 (RushOrder)或动名词(有“-ing”后缀)修饰名词(例如, BillingAddress)。对于方法来说,习惯是访问器方法用小写get开头 (getSalary),更改器方法用小写的set开头(setSalary)。

  • 7.优先使用不可变的类
    LocalDate类以及java.time包中的其他类是不可变的——没有方法能修改对象的状态。类似plusDays的方法并不是更改对象,而是返回状态已修改的新对象。
    更改对象的问题在于,如果多个线程试图同时更新一个对象,就会发生并发更改。 其结果是不可预料的。如果类是不可变的,就可以安全地在多个线程间共享其对 象。
    因此,要尽可能让类是不可变的,这是一个很好的想法。对于表示值的类,如一个 字符串或一个时间点,这尤其容易。计算会生成新值,而不是更新原来的值。
    当然,并不是所有类都应当是不可变的。如果员工加薪时让raiseSalary方法返回 一个新的Employee对象,这会很奇怪。

知识点13:文档注释

这里不做过多的解释,参考这篇参考文章。
https://www.runoob.com/java/java-documentation.html

未完待补充

猜你喜欢

转载自blog.csdn.net/weixin_42684418/article/details/104210591
今日推荐