Java类详解

习惯使用word做笔记,转到博客上来的时候总会有错位,标题号错乱的情况,凑合看看文字,等我改排版委屈

此篇是比较详细的java类讲解,易错点用红色标示了,大家注意啊


Java程序是面向对象的编程,一切程序从类开始。

类是对一系列具有相同属性的对象的抽象的描述。

:人类

对象 :小明,是一个具体的人类的实例(个体)

所有的东西都是对象,包括类也是对象。

 

  1. 面向对象的三大特性
    1. 封装

合理隐藏、合理暴露。即隐藏实现细节、暴露简单的操作。

通常封装要把细节隐藏,直接访问成员变量,就是使用细节,直接使用细节有太多的不可控情况发生。

为了隐藏,java提供了四个访问权限(有三个权限修饰符)

public : 公共的,任何地方都可以看到、访问到

protected : 受保护的,之后子类、当前包、当前类可以访问到

:默认的,包权限,只有当前包、当前类可以访问

private : 私有的,只有当前类可以访问

eg.1

有如下文件结构和代码

User.java

packageorg.fkjava;

 

publicclassUser

{

//包权限

intage;

//私有权限

private Stringname;

//受保护权限

protected Stringgender;

//公开权限

publicintheight;

}

TestUser.java

packageorg;

 

importorg.fkjava.User;

 

publicclassTestUser

{

publicstaticvoid main(String[]args)

{

Useru =newUser();

 

u.age = -100;

u.name ="张三";

u.gender ="";

u.height = 150;

}

}

运行结果:

agenamegender三个变量都不可访问,因为TestUser.javaorg包内,User.javaorg.fkjava包内,两个类不在一个包内。

 

eg.2

将文档结构改为

TestUser.java的代码第一行改为:

packageorg.fkjava;

 

importorg.fkjava.User;

 

publicclassTestUser

{

publicstaticvoid main(String[]args)

{

Useru =newUser();

 

u.age = -100;

u.name ="张三";

u.gender ="";

u.height = 150;

}

}

运行结果:

此时User.javaTestUser.java在同一个包内,所以agegender可以访问,但是nameprivate修饰,只有当前类可以访问,而TestUser是另一个类,所以不可以访问。

 

  1. 封装类型

把基本类型,包装成对象(引用类型)

byte: Byte

short: Short

int: Integer

long: Long

char: Character

float: Float

double: Double

boolean: Boolean

 

封装类型的好处

1.基本类型必须有默认值,封装类型未赋值时为null

2.封装类型具有面向对象编程的特性(封装、继承、多态)。

使用封装类型的时候,不要再使用 > < == !=之类来进行判断(之前出过bug),而使用equals等方法

 

  1. 常用方法

Integer.parseInt(Strings):String转换为int

Byte.parseByte(Strings):String转换为byte

...

除了Character里面没有parseChar方法以外,其他的类,都有对应想parse开头的方法。

 

  1. 基本类型转换封装类型
  • 使用构造器,不推荐使用

Integer i1 = new Integer(10000);

  • 使用静态方法返回一个Integerjava 5之前的推荐方法

Integer i2 = Integer.valueOf(String/int);

Integer i2 = Integer. valueOf (10000);

  • java 5以后,支持自动装箱的功能,可以直接把基本类型赋予给封装类型

//装箱 =基本类型 ->封装类型

Integer i3 = 10000;

java5以后,还能支持自动拆箱

//拆箱=封装类型->基本类型,i3封装类型,i4基本类型,自动拆箱

int i4 = i3;

 

  1. 继承

子类继承父类,会得到父类的一切,但是除了构造器和私有成员外。在调用子类构造器的时候,系统会自动调用父类的构造器,但是构造器并未被继承。

  1. 语法

[public] [ abstract | final ] class <类名> [ extends父类 ]

{

}

extends 是一个动词,表示扩展父类。

 

  1. 规则
  • Java是单继承的,一个类只能继承一个父类。
  • 所有的类,都是Object类的子类或者子孙类。
  • 如果没有自己使用extends关键字进行继承,默认继承java.lang.Object类(所有的都是对象——因为所有的类,最终都是继承了Object)。
  • 子类继承了父类,会得到父类的一切成员变量和方法。除private修饰外,其余都可以访问。
  • 子类继承父类以后,如果父类的方法不能满足子类的需求,可以覆盖(重写、Override)父类的方法,实现扩展。

 

  1. 方法重写/覆盖(override

两个相同:子类方法与父类方法的方法名相同;形参列表相同。

两个相同或更小:返回值类型相同或范围更小(子类);子类方法声明抛出的异常相同或更小

一个相同或更大:访问权限(权限修饰符)要相同或更大。eg.父类方法用protected,子类用public

 

  1. super关键字

引用父类的实例变量

引用父类的实例方法

调用父类的构造器

  1. superthis差别

super调用/引用和this调用/引用是一样的,只是this从当前类开始找,super从父类开始找。它们都表示当前实例。

this调用表示调用当前类的其他构造器,super调用则表示调用父类的构造器。

this调用和super调用不能同时出现在同一个构造器里面,因为它们都是必须在第一行!

注意:如果程序员没有在构造器的第一行写this调用或者super调用,系统会生成一个无参的super调用。

如果父类没有无参构造器,子类必须使用super调用传入合适的参数,来明确调用父类的构造器。

 

3.多态

同一个类型的对象,执行相同的操作,呈现不同的行为。

 

  1.  
    1. 举例

现在有两台电脑,一台实际上是笔记本,一台是服务器,开机是它们共有的方法(操作),笔记本开机通常只需要1分钟,服务器需要半个小时(行为不同)。

publicclassTestComputer

{

publicstaticvoid main(String[]args)

{

//因为Computer包含了NotepadServer,所以NotepadServerComputer的范围内(范围比较小),可以赋予给范围比较大的变量。

Computer c1 = new Notepad();

//Server是服务器,属于电脑的一个子类,Server的范围比较小。

Computer c2 = new Server();

 

//c1c2都是Computer类型的变量,但是实际运行的时候,它们并不是Computer这个父类,而是分属两个子类。

c1.powerUp();

c2.powerUp();

}

}

 

//电脑

class Computer

{

//有个开机的方法

publicvoid powerUp()

{

System.out.println("Computer里面的电脑正在开机:" + this);

}

}

class Notepadextends Computer

{

//笔记本开机,要呈现一个不同行为,必须把父类的方法覆盖

publicvoid powerUp()

{

//调用父类的方法

super.powerUp();

//子类单独输出一下

System.out.println("Notepad里面的电脑正在开机:" + this + ",耗时1分钟");

}

}

class Serverextends Computer

{

//服务器开机,要呈现一个不同行为,必须把父类的方法覆盖

publicvoid powerUp()

{

//调用父类的方法

super.powerUp();

//子类单独输出一下

System.out.println("Server里面的电脑正在开机:" + this + ",耗时30分钟");

}

}

把子类对象直接赋给父类的引用时,当运行时调用该引用类型的方法时,其方法行为总是表现出子类的行为特征,而不是父类的行为特征,这就出现了同一引用调用引用变量的方法时,表现出不同的特征,这就是多态。

 

  1. 编译时类型和运行时类型

Java中的许多对象(一般都是具有父子类关系的父类对象)在运行时都会出现两种类型:编译时类型和运行时类型,编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,会出现所谓的多态。例如:Computerc1 = new Notepad()这行代码将会生成一个Computer变量,该变量的编译时类型是Computer,运行时类型是Notepad

编译时类型用于在用javac的时候检查语法是否正确、成员(变量、方法、构造器)是否存在。

运行时,变量的具体类型可以根据等号赋予的实际对象来决定。

因此,编译Java代码时,引用变量只能调用声明该变量所用类(父类里,即Computer)里包含的方法,否则编译报错。与方法不同的是,对象的属性则不具备多态性。通过引用变量来访问其包含的实例属性时,系统总是试图访问它编译时类所定义的属性,而不是它运行时所定义的属性。

eg.将上节代码中父类ComputerpowerUp方法改为powerUpNew,虽然NotepadServer中有powerUp方法,但则报错

publicclassTestComputer

{

publicstaticvoid main(String[]args)

{

Computer c1 = new Notepad();

Computer c2 = new Server();

 

//编译时c1c2都是Computer类型的变量(实际运行的时候,c1Notepad型,c2Server型)

//所以编译时报错没有为Computer类型定义此方法

c1.powerUp();

c2.powerUp();

}

}

 

//电脑

class Computer

{

publicvoidpowerUpNew()

{

System.out.println("Computer里面的电脑正在开机:" + this);

}

}

class Notepadextends Computer

{

publicvoid powerUp()

{

super.powerUpNew();

System.out.println("Notepad里面的电脑正在开机:" + this + ",耗时1分钟");

}

}

class Serverextends Computer

{

publicvoid powerUp()

{

super.powerUpNew();

System.out.println("Server里面的电脑正在开机:" + this + ",耗时30分钟");

}

}

 

  1. 类型转换

小类可以自动转换为大类的类型(范围小的(子类)对象,可以赋予给范围大的(父类)变量)。

大类变量,要转换为小类变量,需要强制类型转换。(范围大的(父类)对象,转换为范围小的(子类)变量)。

为了避免转换时发生错误,可以用instanceof语句判断

eg.c1可以转换为Notepad类,c2不可以

Computer c1 = new Notepad();

Computer c2 = new Server();

 

booleanb1 =c1instanceof Notepad;//true

booleanb2 =c2instanceof Notepad;//false

但是使用instanceof时必须保证有继承关系,即instanceof后面的数据类型,应该是instanceof之前的变量的类型的子类

booleanb1 =c2instanceof String;

这样写就不行,因为c2Computer类型,并不是String的父类。

 

  1. 类的语法

[public] [abstract | final] class <类名>

{

//类里面的组成部分

}

public : 访问修饰符,使用public修饰的类,java文件的文件名必须和类名相同。

abstract | final |这两个不能同时存在

一个java文件可以写多个的类,但是只能有一个public修饰的类,每个类都可以有main方法。

 

  1. 类里面的组成部分:

成员变量

方法

构造器

 

代码块

内部类、内部接口、内部枚举

 

  1. 类的执行方法

程序执行的时候,先通过java命令找到类名对应的class文件,把class文件加载到内存里面。

类被加载以后,就会到类里面查找main方法,参数必须是String[]的,找到方法后,执行方法。

1.找类

2.找类里面的main方法

3.调用main方法

publicclassTestHuman

{

publicstaticvoid main(String[]args)

{

System.out.println("TestHuman");

}

}

 

 

class Human

{

publicstaticvoid main(String[]args)

{

System.out.println("Human");

}

}

在命令行里输入java TestHuman

输出

TestHuman

输入java Human

输出

Human

 

  1. 成员变量

<数据类型> <变量名> [=初始值];

成员变量通常可以认为是"人"的属性。

当变量写到方法里面的时候,变量是局部变量,仅在方法内有效。

当变量写到类里面的时候(方法外面),变量就是成员变量,在整个类里面都可以访问到。

 

成员变量多了一些修饰符

[public | protected | private] [static] [final] [transient] <数据类型> <变量名> [= 初始值];

权限修饰符,三选一

public | protected | private

静态范围标记

static

如果有static修饰表示属于类;没有static修饰属于实例。使用了static的变量,不管创建几个实例,所有实例中的这个变量值都相同=最后一个实例的变量值。类成员在类存在的时候,就已经存在;实例成员必须要实例存在才能存在。

eg.使用static修饰那么,两只狗的名字都输出二黄

publicclassDog

{

//狗的名字

static Stringname;

 

//狗的年龄

intage;

}

 

class TestDog

{

publicstaticvoid main(String[]args)

{

//造第一只狗

Dog d1 = new Dog();

//第一只狗的名字

d1.name ="大黄";

d1.age = 10;

 

//第二只狗

Dog d2 = new Dog();

d2.name ="二黄";

d2.age = 8;

 

 

//分别输出两只狗的名字以及年龄

System.out.println(d1.name);//

System.out.println(d2.name);//二黄

 

System.out.println(d1.age);//10

System.out.println(d2.age);//8

}

}

static的情况,每个实例都有各自的name

static的情况,所有实例的name值都是属于类的

final

如果有final修饰,表示变量只能赋予一次的值。

瞬间的

transient 使用此修饰符修饰的,在执行序列化的时候,不会被转换。不能和static同时使用。

 

  1. 方法

方法就是操作,在以前的面向过程的编程语言里面,通常称之为"函数",现在一些面向对象的编程语言也称之为是"函数"。

比如"门"这个类型的一个对象,可以有打开、关闭两个常见的动作,这些动作是需要被其他的(人类型的)对象使用的。

  1. 语法

[修饰符] <返回值类型> <方法名>([形参列表])

{

//方法体,执行语句

}

 

  1. 修饰符

public | protected | private

static

static修饰的方法为类方法,而非实例方法,对于这个类构造的所有实例,这个方法都相同,可以通过类名来调用。没有static修饰的方法,通过对象(实例)来调用。

    static修饰的方法中不能使用this引用。也不能访问非static修饰的普通成员。

final | abstractfinalstatic也不能同时存在

 

  1. 返回值类型

void : 特殊的返回值类型,表示不需要返回值,如果返回值类型里面不是void,那么必须包含有效的return语句。

除了void之外,任何的数据类型都可以作为返回值类型。但是只能返回一个变量。

返回什么类型的值,就该使用对应的类型的变量来接收。

如果可以强转,也可以强转后接收。

 

  1. 形参列表

方法的参数是可选的,由定义方法的时候决定。

使用方法的时候,如果方法定义了要形式参数(形参),那么必须提供实际的参数(实参)

一个方法可以有多个参数,每个参数之间使用逗号隔开。

每个参数必须明确指定类型。

形参都不能用等号赋予值,而是在调用方法的时候,传递实参进来的。

可以将低位的变量传给高位的,eg. byte可以自动转化为int

publicclassTestMethodArguments

{

publicstaticvoid main(String[]args)

{

TestMethodArgumentst =new TestMethodArguments();

 

//直接给参数传递直接量

t.test1( 5 );

 

//给方法的参数传递变量

inti1 = 10;

t.test1(i1 );

 

 

//给方法的参数传递变量,但是类型不一样

//虽然类型不同,但是byte能够自动转换为int,所以可以用

byteb1 = 15;

t.test1(b1 );

 

//方法要的是int,但是给的是long,就不行,需要强制类型转换

longL1 = 199;

 

//相当于在执行test1方法之前,先执行了:

//int i = (int)L1;

//参数有值,然后才能执行方法

t.test1( (int)L1 );

}

 

//第一个测试方法,要求一个int类型的参数

void test1(inti )

{

System.out.println("参数的值 : " +i );

}

}

 

  1. 参数传递机制

编程语言的参数传递方式,主要分为引用传递和值传递,而Java只能支持值传递参数

每次把参数传递给方法、构造器的时候,始终把参数的值,复制一份给方法、构造器里面。

值传递的本质,就是把变量的值,复制一个副本,传递给方法里面。

基本类型的值,就是变量的值;

引用类型的值,是对象的内存地址。所以可以改变地址指向的内存的值

 

  1. 方法的重载(Overload)

定义:在同一个类的相同方法名,不同的形参列表,就是方法的重载。

同名方法被调用的时候,实参是什么类型的,就调用对应形参类型的方法。

规则

     同一个类

     相同的方法名

     不同的形参列表

         形参的类型不同

         形参的类型相同,但是形参的个数不同

         形参的类型、个数都相同,但是形参的顺序不同

         ×形参类型、个数、顺序都相同,但是参数的名称不同

         ×形参类型、个数、顺序都相同,但是方法的返回值不同

         ×形参类型、个数、顺序都相同,但是方法的修饰符不同

 

  1. 参数可变的方法

Java 5开始提供,本质上是一个数组

  1. 语法

<数据类型>... <参数名>

    规则

         一个方法,只能有一个形参个数可变的参数

         如果方法有多个参数,形参个数可变的参数,必须放到参数列表的最后

eg.

publicclassTestMultiArguments

{

publicstaticvoid main(String[]a)

{

TestMultiArgumentst =new TestMultiArguments();

//调用test方法的时候,可以直接给多个参数,也可以给一个数组

 

//直接给任意个数的值

//6

//[1,2,3,4,5,6]

t.test(1,2,3,4,5,6);

 

//把数组作为参数

//5

//[5,6,7,8,9]

int[]v =newint[]{5,6,7,8,9};

t.test(v);

}

 

void test(int...a)

{

//a变量就是一个数组,并且数据类型是int类型的数组

System.out.println(a.length );

System.out.println( java.util.Arrays.toString(a) );

}

 

 

void test3(inta,int...j)

{

}

}

 

  1. 方法递归

方法执行体中,再次调用该方法本身。相当于是一种循环

规则

必须有结束点,即保证在某个时间,不要导致无限递归

必须向已知的方向递归

先调用的,后返回。

注意

每调用一个方法,就会为方法分配一个独立的栈空间(也叫方法内存、函数内存)。不断递归会造成栈内存不足,会出现"栈溢出错误(StackOverflowError)"。

 

  1. 构造器

用于产生一个对象(实例)。

Java里面不可能定义没有构造器的类,类最少会有一个构造器。如果程序员没有指定(定义)构造器,系统会自动生成一个没有参数的"默认构造器"。程序员已经指定(定义)构造器(不管是否有参数),系统都不会再生成默认的构造器。

 

基本上和方法差不多,只是构造器不能有返回值、不能有static修饰不允许递归。

构造器的重载和方法的重载差不多:形参列表不同即可,构造器的名字必须和类名相同。

this调用只能放到构造器第一行代码,用于调用当前类的其他构造器。(七内详解)

this引用用于表示当前实例,调用者是哪个对象,this就表示哪个对象。(七内详解)

 

  1. 语法

[修饰符] <类名>([形参列表])

{

//不需要返回值

}

修饰符

public | protected | private

形参列表

规则和方法的形参列表的规则一样。

构造器必须通过new关键字类调用,唯一的作用就是产生实例。

每被new调用一次,构造器就执行一次,于是产生了一个实例。

 

  1. 代码块

在类里面,任何一个使用{}包起来的内容,就是代码块。

代码块的存在,是为了提高代码的重用。

 

  1. main方法执行的过程:
  • 把类加载到内存里面。
  • 根据名字和参数找到类里面参数为String[]类型的main方法。
  • 因为main方法必须是public static修饰的,于是调用main方法等于利用类名调用方法

    类名.main(args);

     

  1. 初始化代码块

在类里面、方法和构造器的外面的代码快,没有名字的{}。就是初始化代码块。

publicclassTestCodeBlock

{

//初始化代码块

{

System.out.println("代码块1");

}

 

publicstaticvoid main(String[]args)

{

    System.out.println("main");

}

 

//初始化代码块

{

System.out.println("代码块2");

}

}

 

  1. 实例初始化代码块(非静态初始化代码块)

没有static修饰的代码块,就是属于实例的初始化代码块。

这些代码块执行的时候从上往下执行,所有的实例初始化代码块执行完成以后,才能执行构造器。每次new构造器之前都会执行一次。

publicclassTestCodeBlock

{

 

//初始化代码块

{

System.out.println("代码块1");

}

 

public TestCodeBlock()

{

System.out.println("构造器");

}

 

publicstaticvoid main(String[]args)

{

System.out.println("main");

 

TestCodeBlock t1 = new TestCodeBlock();

 

System.out.println("======================");

 

TestCodeBlock t2 = newTestCodeBlock();

}

//初始化代码块

{

System.out.println("代码块2");

}

}

运行结果:

  1. 类初始化代码块(静态初始化代码块)

static修饰的,属于类的初始化代码块。

这些代码块执行的时候,依然从上往下,会在第一次主动使用类的时候,被执行一次

eg在调用main方法的时候,其实就是第一次使用TestCodeBlock这个类,所以在此之前执行了静态代码块

publicclassTestCodeBlock

{

 

//初始化代码块

{

System.out.println("代码块1");

}

static

{

System.out.println("静态代码块1");

}

public TestCodeBlock()

{

System.out.println("构造器");

}

publicstaticvoid main(String[]args)

{

System.out.println("main");

 

TestCodeBlock t1 = new TestCodeBlock();

 

System.out.println("======================");

 

TestCodeBlock t2 = new TestCodeBlock();

}

//初始化代码块

{

System.out.println("代码块2");

}

static

{

System.out.println("静态代码块2");

}

}

总结:执行顺序:静态代码块(先父类后子类)->父类非静态代码块->父类构造器->子类非静态代码块->子类构造器

 

  1. 变量详解

5.1.局部变量

方法里面声明的变量,就是局部变量。

局部变量包括:

方法、构造器、代码块里面声明的变量、方法和构造器的参数

规则:

局部变量必须赋予值以后才能使用,系统不会赋予默认值。

局部变量唯一可以使用的修饰符是final。加上final表示不能被再次赋值。

 

5.2.成员变量

没有final修饰的成员变量,系统会赋予默认值,整数为0、浮点为0.0booleanfalse、引用类型为null

 

5.2.1类变量

static修饰的成员变量,就是类变量。属于类,而不属于实例。

不推荐使用实例来访问类变量,而是直接通过类进行访问。即类名.变量(不是实例.变量)

eg.

System.out

// 公共的、静态的、最终的,数据类型类型为PrintStream的类变量,名为out

public static final PrintStream out

eg.使用方法

package shuzu;

 

publicclassTestClassVariable

{

staticinti;

 

publicstaticvoid main(String[]args)

{

//创建一个实例

TestClassVariablet2 =new TestClassVariable();

//利用实例,输出类变量的值

System.out.println(t2.i );

 

//i变量的赋予为600

t2.i = 600;

// t2.i在系统编译后,会自动转换为 TestClassVariable.i

System.out.println(t2.i );//600

 

//直接通过类访问i变量

System.out.println( TestClassVariable.i );//600

}

}

 

5.2.2实例变量

没有static修饰的成员变量,就是实例变量。属于实例,而不属于类。

实例变量,只能通过实例来访问。每个实例,各自持有一份实例变量。

 

  1. 参数传递机制
  2. this关键字

永远表示当前实例

  1. this引用

语法:this. xxx

表示引用new的这一瞬间产生的当前实例。变量、方法的查找范围直接从当前类的实例成员里面开始找。

如果在当前类里面没有找到,会自动找父类的成员。调用者是谁,this就代表谁。

 

  1. this调用

语法:this()

用于调用当前类的其他不同参数的构造器。

一个类可以有多个不同参数的构造器,具体调用哪个构造器,通过参数列表决定。

优点:用于提高代码的重用度。软件技术的发展,就是在不断提高程序的重用度、可读性。代码的重用度越高,意味着人们写了更少的重复的代码。

this调用永远只能放在构造器的第一行代码!

eg. 使用this调用提高代码重用度

class Computer

{

longmemorySize;

String cpuType;

 

Computer( longmemorySize, StringcpuType)

{

//变量查找的时候,使用"就近原则"查找。所以在构造器、方法里面使用变量的时候,如果参数名和成员变量名是同名的,那么会找到参数。因为参数和执行语句更靠近。

    //这个等于局部变量memorySize自己赋值给自己,并没有调用到类的成员变量

    memorySize =memorySize;

    

//===============this引用的使用方法=============================================

//this永远表示当前实例

//在new的一瞬间,实例已经产生了,在构造器里面使用this.表示访问当前实例里面的成员变量。

this.memorySize =memorySize;

this.cpuType =cpuType;

}

 

//===============this调用的使用方法==========================================

Computer()

{

//给内存大小、CPU一些默认值

//this.memorySize = 2000;

//this.cpuType = "Intel i3";

 

//使用this调用提高代码的重用度,下面这行代码与上两行效果相同

    //this(long,String)调用了构造器Computer( long memorySize, String cpuType)

this(2000,"Intel i3");

//必须要使用合适的参数列表来决定调用哪个构造器(只能调用不同参数的构造器),不可以写this()!!!这样this()调用Computer(),Computer()调用this(),一直不会结束

}

 

}

 

publicclassTestComputer

{

publicstaticvoid main(String[]args)

{

}

}

 

  1. Object

所有的类,最终都是继承了Object类,是所有类的开始。这个是Java里面唯一没有父类的类。

里面提供了所有对象都非常常用的操作(方法):

equals:比较两个对象是否相等。通过比较内存地址

    源码:

publicboolean equals(Object obj)

{

returnthis == obj;

}

hashCode: 如果两个对象使用equals方法比较返回true,那么hashCode也应该返回相同的int值。可以认为,hashCode就是内存地址。

toString:把对象转换为String,转换为String以后才能方便输出。

getClass:返回对象所属的Class对象

 

重写Object的方法

上面几个方法也经常在子类中被重写(不是fianl的可以重写),比如现在要比较两个学生对象是否相等,如果认为姓名一样,学生就是同一个,这个时候需要重写equals方法(函数名和参数必须相同,即参数必须写Object obj)。

publicboolean equals(Object obj)

{

if(this == obj )

{

//表示内存地址相等,对象一定是相等的

//这里return以后,后面还有代码是不会继续执行的

returntrue;

}

 

//判断obj是否为Student的实例,需要强制类型转换,然后判断name是否相等

if( objinstanceof Student )

{

Student s = (Student) obj;

// this.name就是调用者的name

// s.name就是objStudent的时候,obj里面的name

if(this.name.equals( s.name ) )

{

//如果这两个name相等,表示对象相等

returntrue;

}

}

 

//其他的任何情况,都return false

//obj不是Student的实例、name不相等

returnfalse;

}

此时为了保持hashcode方法返回的值也相同,重写hashcode方法,改为返回namehashcode

//equals返回truehashCode也应该返回相同的值

//hashCode的作用,主要就是为了识别对象的特性(属性)是否一致

publicint hashCode()

{

//因为比较对象是否相等的时候,就使用了String类型的name作为比较的依据

//那么在返回hashCode的时候,完全可以使用String里面的hashCode

//实际上会使用Objects类里面hash方法去把所有的属性放到此方法里面去计算hash

 

// java 7之前没有Objects

//没有Objects类的时候,可以选择使用 Arrays.hashCode,把要计算hash的成员全部放到里面去计算return name.hashCode();

 

return Objects.hash(name);

}

 

 

  1. packageimport
    1. package包,命名空间

作用:把多个同名的类,放到不同的目录。

语法

必须放到源代码的第一行,在import之前。

package <包名>;

 

包名是一个标识符,可以有多段组成,每段使用.隔开。

每个.相当于就是一级目录。

 

package org.fkjava.oa;

在这个包下面的class编译后会放到 org/fkjava/oa目录下面。

oa是项目名,src是源代码,bin是编译后的class文件

 

oa

src

org

fkjava

oa

workflow

User.java

hrm

User.java

 

TestUser.java

bin

org

fkjava

oa

workflow

User.class

hrm

User.class

TestUser.class

 

编译程序的命令

首先要cdoa项目里面

-d参数表示用于指定生成的class文件放到哪个目录,默认放到当前目录。

如果有-d的参数,java命令会自动根据package生成子目录。

 

1.编译hrm里面的User

Windows : javac -d bin src/org/fkjava/oa/hrm/User.java

Windows : javac -d bin src\org\fkjava\oa\hrm\User.java

2.编译workflow里面的User

Windows : javac -d bin src/org/fkjava/oa/workflow/User.java

Windows : javac -d bin src\org\fkjava\oa\workflow\User.java

3.编译TestUser

 

因为使用了不是当前目录的包,并且class文件在bin目录下,所以必须使用 -cp 参数指定类的搜索目录。

cp = CLASSPATH =类路径,是javajavac命令用来搜索class文件的参数。默认是运行命令的当前目录。

 

如果没有指定cp参数,也可以通过,也可以通过设置CLASSPATH环境变量的方式来实现查找。

CLASSPATH的值就是类的搜索路径。多个路径使用分号隔开(非Windows使用冒号隔开)。

 

Windows : javac -cp bin -d bin src/org/fkjava/oa/TestUser.java

Windows : javac -cp bin -d bin src\org\fkjava\oa\TestUser.java

 

 

4.运行TestUser

也必须通过 -cp参数指定类的搜索路径

java命令后面的类名,必须使用类的全名包名.类名格式

 

java -cp bin org.fkjava.oa.TestUser

 

import

 

导入另外一个包下面的类,用于简化类名。

 

类的全名包名.类名格式

 

Random类的全名是 java.util.Random,如果没有import,就必须使用全名才能使用Random

import的时候,就可以直接使用Random,省略掉了包名。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值