黑马程序员---面向对象---类

---------------------- Java开发Android培训、期待与您交流! ----------------------


1.1 定义类

定义一个类而言,可以包含三种最常见的成员:构造器、属性和方法,三种成员都可以定义零个或多个。

[修饰符] class 类名 {

    零个到多个构造器定义

零个到多个属性

零个到多个方法

}

 

属性用于定义该类或该类的实例所包含的数据,方法则用于定义该类或该类的实例的行为特征或功能实现,构造器用于构造该类的实例,Java通过new关键字来调用构造器。

 

构造器是一个类创建对象的根本途径,如果程序员没有为一个类编写构造器,则系统会为该类提供一个默认的构造器(无参构造器)。如果程序员为类提供一个构造器,系统将不再为该类提供构造器。

[修饰符] 属性类型 属性名 [=默认值]

  •  修饰符:可以省略,也可以是public、protected、private、static、final,其中public、protected、private三选一,可以与static、final组合起来使用。
  •  属性类型:可以是Java语言允许的任何数据类型,包括基本数据类型和引用数据类型。
  •  属性名:只要是一个合法的标识符即可,可读性来讲,属性名应该由一个或多个有意义的单词连缀而成,第一个单词首字母小写,后面每个单词首字母大写,其他字母全部小写,单词与单词之间不需要任何分隔符。
  •  默认值:定义属性还可以定义一个可选的默认值。

 

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

}

 

  •  修饰符:可以省略,也可以是public、protected、private、static、final、abstract,其中public、protected、private三选一,abstract 和final最多只能出现其中之一,可以与static组合起来使用。
  •  方法返回值类型:可以是Java语言中的任何类型,,如果声明了方法返回值类型,则方法体内必须有一个return语句,该语句返回一个变量或一个表达式,这个变量或表达式的类型必须与声明的类型匹配。除此之外,如果一个方法没有返回值,则必须用void来声明。
  •  方法名:同属性名命名规则相同,但通常建议以英文中的动词开头。
  •  形参列表:形参列表用于定义该方法可以接受的参数,有0个到多个“参数类型 形参名”组合而成,多组参数之间用逗号隔开。

 

[修饰符] 构造器名(形参列表){

}

  •  修饰符:可以省略,也可以是public、protected、private其中之一。
  •  构造器名:构造器名必须同类名相同(大小写严格一致)。
  •  形参列表:同方法的形参列表。

1.2 对象的产生和使用

创建对象的根本途径是构造器,通过new关键字来调用某个类的构造器即可创建这个类的实例。

class Person {

public String name;

public int age;

public Person() {

    System.out.println(“Create a Person!”);

}

public void say(String info) {

    System.out.println(info);

}

}

 

public void static main(String[] args) {

Person p;

p = new Person();

p.name = “zsj”;

p.age = 100;

p.say(“Programming for fun!”);

}

大部分时间,定义一个类就是为了重复创建该类的实例,同一个类的多个实例具有相同的特征,而类则是定义了多个实例的共同特征。

 

1.3 对象、引用和指针

Person p = new Person();

这行代码实际上产生了两个实体:一个是p变量,一个是Person对象。

从Person类定义来看,Person对象应包括两个属性,而属性是需要内存来存储的。因此,当创建Person对象时,必然需要有对应的内存来存储Person对象的属性。

栈内存中的引用变量并未真正存储对象里的属性数据,对象的属性数据实际存放在堆内存里。而引用类型变量仅仅只是指向该对内存里的对象。从这个角度来看,引用型的变量与C语言里的指针很像,它们都是存储一个地址值,通过这个地址值来引用到实际对象。

如果对内存里的对象没有任何变量指向该对象,那么程序无法再访问该对象,这个对象也就成了垃圾,Java的垃圾回收机制将会回收该对象,释放该对象所占的内存区。(将引用变量赋值为null)。

1.4 对象的this引用

Java提供了一个this关键字,this关键字是一个对象的默认引用。this关键字总是指向调用该方法的对象。根据this出现位置的不同,this作为对象的默认引用有两种情形:

  •  构造器中引用该构造器执行初始化对象。
  •  在方法中引用调用该方法的对象。

this关键字最大的作用就让类中一个方法,访问该类的另一个方法或属性。例子如下

public class Dog {

public void jump() {

    System.out.println(“I can jump!”);

}

public void run() {

    Dog d = new Dog();

d.jump();

    System.out.println(“I am running!”);

}

}

 

public class TestDog {

public static void main(String[] args) {

    Dog dog = new Dog();

    dog.run();

}

}

代码产生了两个Dog对象,问题:

(1) 在run方法中调用jump方法时是否一定需要一个Dog对象?

(2) 是否一定需要重新创建一个Dog对象呢?

答案:第一个是肯定的,因为没有使用static修饰的属性和方法都必须使用对象来调用,第二个问题是否定的,因为当程序调用run方法时,一定会提供一个Dog对象,应该使用这个对象而不用新建对象了。

使用this关键字可以满足这个需求:

this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的对象只能是当前类;只有当这个方法被调用时,它所代表的对象才被确定下来:谁在调用这个方法,this就代表谁。

public class Dog {

public void jump() {

    System.out.println(“I amjumping!”);

}

Public void run() {

    this.jump();

    System.out.println(“I am running!”);

}

}

Java允许对象一个成员直接调用另一个成员,可以省略this前缀。

public class Dog {

public void jump() {

    System.out.println(“I amjumping!”);

}

Public void run() {

    jump();

    System.out.println(“I am running!”);

}

}

 

大部分时间,普通方法访问其它方法、属性时不必使用this关键字,但如果这个方法里有个局部变量和属性同名,但程序有需要在这个方法里访问这个被覆盖的属性,则必须使用this前缀。

除此之外,this引用也可以用于构造器中作为默认引用,由于构造器是直接使用new关键字来调用,而不是使用对象来调用,所以this在构造器中引用的是该构造器进行初始化的对象。

public class ThisInConstructor {

public int foo;

public ThisInConstructor() {

    int foo = 0;

this.foo = 6;

}

 

public static void main(String[] args) {

    System.out.println(new ThisInConstructor().foo);

}

}

在ThisInConstructor构造器中使用this引用时,this总是指向引用该构造器正在初始化的对象,this.foo = 6;将正在执行初始化的ThisInConstructor对象的foo属性设为6,这意味着该构造器返回的所有对象的foo属性都等于6.

当this作为对象的默认引用使用时,程序可以像访问普通引用变量一样来访问this引用,甚至把this当做返回值。

public class ReturnThis {

public int age;

public ReturnThis  grow() {

    age++;

    return this;

}

public static void main(String() args) {

    ReturnThis rt = new ReturnThis();

rt.grow().grow().grow();

System.out.println(“rt is: ” + rt.age);

}

}

1.5 方法重载

Java允许同一个类里定义多个同名方法,只要形参列表不同就可。如果同一个类中包含了两个或两个以上方法的方法名相同,但形参列表不同,则被称为方法重载

在Java程序中需要确定一个方法需要三个要素:

  •  调用者,也就是方法的所属者,既可以是类,也可以是对象。
  •  方法名,方法的标识。
  •  形参列表,当调用方法时,系统将会根据传入的实参列表匹配。

方法重载的要求就是两同,一不同:同一个类中方法名相同,参数列表不同。至于方法的其他部分,如方法的返回值类型、修饰符等,与方法重载没有关系。

public class Overload {

//下面定义了2个test方法,但方法的形参列表不同

//系统可以区分这两个方法,这种被称为方法重载

public void test() {

System.out.println("无参数");

}

public void test(String msg) {

System.out.println("重载的test方法 " + msg);

}

public static void main(String[] args) {

Overload ol = new Overload();

//调用test时没有传入参数,因此系统调用上面没有参数的test方法。

ol.test();

//调用test时传入了一个字符串参数,因此系统调用上面有一个字符串参数的test方法。

ol.test("hello");

}

}

 

public class OverloadVarargs {

public void test(String msg) {

System.out.println("只有一个字符串参数的test方法 ");

}

//因为前面已经有了一个test方法,test方法里有一个字符串参数。

//此处的长度可变形参里不包含一个字符串参数的形式

public void test(String... books) {

System.out.println("*******形参长度可变的test方法****** ");

}

 

public static void main(String[] args) {

OverloadVarargs olv = new OverloadVarargs();

//下面两次调用将执行第二个test方法

olv.test();

olv.test("aa" , "bb");

//下面将执行第一个test方法

olv.test("aa");

//下面将执行第二个test方法

olv.test(new String[]{"aa"});

 

}

}

如果同一个类中既有长度可变参数test(String... books),又有test(String msg),则test(String... books)不能通过直接传入一个参数,如果要传入一个参数的test(String... books),只能通过数组。一般不使用长度可变参数的重载。

1.6 成员变量和局部变量

在Java语言中,根据定义变量的位置不同,可以将变量分成2大类:成员变量和局部变量。成员变量和局部变量运行机制存在较大差异

  • 成员变量:指在类范围里定义的变量,也就是前面所说的属性。
  • 局部变量:指在一个方法内定义的变量。

  1. ***变量的使用规则***


不要过分的使用成员变量而不考虑使用局部变量,成员变量存放在堆内存中,成员变量的作用域将扩大到类存在范围或者对象存在范围,这种范围的扩大有一定的害处:(1)增大了变量的生存时间,这将导致更大的系统开销;(2)扩大了变量的作用域,这不利于提高程序的内聚性。

需要考虑使用成员变量的情况:

1、 如果需要定义的变量是用于描述某个类或某个对象的固有信息。

2、 如果在某个类中需要以一个变量来保存该类或者实例运行时的状态信息。

3、 如果某个信息需要在某个类的多个方法之间进行共享。

即使在程序中使用局部变量,也尽可能地缩小局部变量的作用范围,局部变量的作用范围越小,它在内存中停留的时间就越短,程序的性能就越好。因此,能用代码块局部变量的地方就坚决不用方法局部变量。

2 隐藏和封装

2.1理解封装

封装:是面向对象的三大特征之一(另外两个是集成和多态),它是指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过该类所提供的方法来实现对内部信息的访问和操作。

2.2使用访问控制符

private:如果类里的一个成员(包括属性和方法)使用private访问控制符来修饰,则这个成员只能在该类的内部被访问。显然,这个访问控制符用于修饰属性最合适,可以把属性隐藏在类得内部。

default(包访问权限):如果类里的一个成员(包括属性和方法)或者一个顶级类不使用任何访问控制修饰符,我们就称它是默认访问控制,default访问控制的成员或顶级类可以被相同包下的其他类访问。

protected(子类访问权限):如果类里的一个成员(包括属性和方法)使用protected访问控制符来修饰,那么这个成员既可以被同一个包中其他类访问,也可以被不同包中的子类访问。通常情况下,如果使用protected来修饰一个方法,通常是希望其子类来重写这个方法。

public(公共访问权限):这是最宽松的访问控制级别,如果类里的一个成员(包括属性和方法)或者一个顶级类使用了public修饰,这个成员或顶级类可以被所有类访问,不管是否在同一个包中,或具有父子继承关系。

 

2.3 例子

在ClassA中,可以访问自身的var1、var2、var3和var4变量。

package mypack1;

public class ClassA {

public int var1;

protected int var2;

int var3;

private int var4;

public void method() {

var1 = 1;

var2 = 1;

var3 = 1;

var4 = 1;

ClassA a = new ClassA();

a.var1 = 1;

a.var2 = 1;

a.var3 = 1;

    a.var4 = 1;

}

}

在ClassB中,可以访问ClassA的var1、var2和var3变量。

package mypack1;

class ClassB {

public void method() {

ClassA a = new ClassA();

a.var1 = 1;

a.var2 = 1;

a.var3 = 1;

a.var4 = 1;   //编译错误 ,因为访问private

}

}

在ClassC中,可以访问ClassA的var1、var2变量。

package mypack2;

import mypack1.ClassA;

class ClassC extends ClassA {

public void method() {

var1 = 1;

var2 = 1;

ClassA a = new ClassA();

a.var1 = 1;

a.var2 = 1;

a.var3 = 1;

a.var4 = 1;

}

}

在ClassD中,可以访问ClassA的var1变量。

package mypack2;

import mypack1.ClassA;

class ClassD {

public void method() {

ClassA a = new ClassA();

a.var1 = 1;

a.var2 = 1;

a.var3 = 1;

a.var4 = 1;

}

}

ClassB是默认访问级别,位于mypack1包中,只能被同一个包中的ClassA访问,但不能被mypack2包中的ClassC和ClassD访问。

package mypack2;

import mypack1.ClassB;

class ClassD {

public void method() {

ClassB b = new ClassB();

}

}

 

 

2.4访问控制符的使用,存在以下几条原则:

类里的绝大部分属性应该使用private修饰,除了一些static修饰的、类似全局变量的属性,才可能考虑使用public修饰。除此之外,有些方法只是用于辅助实现该类的其他方法,这些方法被称为工具方法,工具方法也应该使用private修饰。

如果某个类主要用作其他类得父类,该类里包含的大部分方法可能仅希望被其子类重写,二不想被外界直接调用,则应该使用protected修饰。

希望暴露给其他类自由调用的方法应该使用public修饰。因此,类的构造器通常使用public修饰,用来给其他类创建该类的对象。大部分顶级类也用public修饰。

 



 

---------------------- Java开发Android培训、期待与您交流! ----------------------详细请查看:www.itheima.com


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值