类与对象
面向对象的核心思想
面向对象的核心思想:抽象
【抽象是对具体对象(问题)进行概括,抽出这一类对象的公共性质并加以描述的过程】
抽象的关键是抓住事物的两个方面:属性和功能。抽象的目的是从具体的实例中抽取共有属性和功能形成一种数据类型。
在面向对象的程序设计中,抽象包括了:1) 封装(信息隐藏) 2) 继承(复用) 3) 多态
【下面主要体现的是面向对象的第一个特性——封装】
类
类是组成Java程序的基本要素。类封装了一类对象的属性和行为。类是用来定义对象的模板,是一种数据类型。
类的实现包括两部分:类声明和类体。
基本格式为:
class 类名{ //class是关键字,“class 类名”是类的声明部分
类体的内容
} //两个大括号以及之间的内容是类体
类声明
类的名字要符合标识符规定,给类命名时,一般采用下列编程风格(不是语法要求的,但应当遵守):
1) 类名最好是容易识别,见名知意;
2) 类名若使用拉丁字母,首字母大写,当类名是几个“单词”复合时,每个“单词”的首字母使用大写(大驼峰)。
类体
写类的目的是通过抽象描述一类事物的共有属性和行为,给出用于创建具体实例的一种数据类型,描述过程由类体来实现。
类声明之后的大括号及大括号之间的内容称作类体,而大括号之间的内容称为类体的内容。
类体的内容由两部分构成:一部分是变量的声明,用来刻画属性;另一部分是方法的定义,用来刻画行为。
成员变量
变量声明部分声明的变量被称为成员变量或域变量。成员变量又称为属性或者字段。
1. 成员变量的类型
成员变量的类型可以是Java中的任何一种数据类型。
2. 成员变量的有效范围: 成员变量在整个类内中都有效,其有效性与它在类体中书写的先后位置无关。(不提倡把成员变量的声明分散地书写,习惯地先介绍属性再介绍行为)
3. 编译风格
1)一行只声明一个变量
2)变量的名字符合标识符规定,名字若使用拉丁字母,首字母小写,当名字是几个“单词”复合时,从第二个“单词”开始的首字母使用大写(小驼峰)。
3)变量的名字见名知意,避免使用容易混淆的名字(eg 1与l相互邻接)
方法
方法的定义包括两部分:方法声明和方法体,一般格式:
方法声明的部分{
方法体的内容
}
1. 方法声明: 包括方法名和方法的返回值类型(方法的类型),方法的参数。
【方法名必须符合标识符规定,方法名命名习惯和变量名命名一样,采用小驼峰】
2. 方法体: 由方法声明之后的一对大括号以及之间的内容构成。
3. 区分成员变量和局部变量
方法体中声明的变量和方法的参数被称作局部变量。与类的成员变量不同的是,局部变量只在声明它的方法内有效,且与其声明的位置有关。方法参数在整个方法内有效,方法内的局部变量从声明它的位置开始有效。
注意:
如果局部变量和成员变量的名字相同,则成员变量被隐藏,即这个成员变量在这个方法内暂时失效,如果想在该方法中使用被隐藏的成员变量,必须使用this关键字(下面会介绍)。
参数传值方式
方法的声明中出现的参数为形式参数(形参),方法调用时出现的参数为实际参数(实参)。形参是局部变量,实参可以是局部变量,成员变量或常量(但必须是具体的值)。无论是哪一种,实参和形参是不同的量(尽管值相同),占据不同的内存空间。
注意:实参和形参的数据类型必须一致。
方法调用时发生传值过程,即将实参的值赋给形参的过程(形参变量的值是实参的值的拷贝).
根据实参和形参的类型的不同,传值过程分为两种:
1.按值传递:当实参和形参为基本数据类型时。实参的数据类型的级别不可以高于形参的数据类型的级别。
2.按引用传递:当实参和形参是引用类型时。传的是地址值,即“引用”,而不是变量所引用的实体。
可变参数
可变参数是指在声明方法时不给出参数列表中从某项直到最后一项参数的名字和个数,但这些参数的类型必须相同。可变参数使用“…”表示若干个参数。
最后一个参数必须是参数列表中的最后一个参数,这个参数称为方法的参数列表中的可变参数的 “参数代表” 。参数代表可以通过下标运算来表示参数列表中的具体参数。
eg public void f(int ... x)那么f的参数列表从第一个至最后一个的参数都是int型,但是个数不确定。称x是方法f的参数列表中的可变参数的参数代表,可以用x[0],x[1],...,x[m]来表示参数列表第一个至第m+1个参数。
如果对于方法的参数需要灵活变化,那么使用参数代表可以使方法的调用更加灵活方便。
//注意:一个类中的方法,是可以以该类本身为参数类型和返回值类型
Class A{
A a=new A(); //错误
A f(A b){ //正确
A c=new A();
b=c;
return c;
}
}
需要注意:
成员变量是定义在方法之外,类体之内的变量,但对成员变量的操作只能放在方法中,即类体中不可以有变量声明和方法定义以外的其他语句,eg
class A{
int a;
float b;
b=921;//非法,这是赋值语句,不是变量声明
void f(){
b=118; //合法
int x=a+b;
System.out.println("x="+x);
}
}
对象的创建
类是一种数据类型,就可以用类来声明变量。
在面向对象语言中,用类声明的变量被称作对象(实际是引用,但是对象和引用两词常常混作一谈)
与基本数据类型不同的是,在用类声明对象(实际上是引用,在栈中)后,不能直接使用,还必须为声明的对象分配变量(即创建真正的对象,在堆中)后才能使用。
【类是创建对象的模板,没有类就没有对象。当使用一个类创建一个对象时,也称给出了这个类的一个实例。】
构造方法
构造方法是类中的一种特殊方法,当用类创建对象时需要调用它的构造方法。
1. 构造方法的名字和类名相同,且没有返回值类型
2. 允许类中编写多个构造方法,但需要保证它们的参数不同(参数个数或参数类型不同)
3. 如果自己在类中没有编写构造方法,当用new运算符创建该类的对象时,系统会调用默认构造方法,默认构造方法是无参数的,且方法体中没有语句,如果自己编写了一个或多个构造方法,Java系统不会提供这个默认构造方法。
创建对象
创建一个对象包括对象的声明(实际上是声明了引用变量,内存在栈中)和为对象分配变量(真正的对象,内存在堆中)。
对象(引用)的声明
一般格式:类的名字 对象的名字;
eg Rectangle r;这里Rectangle为一个类的名字,r为我们声明的对象(引用变量)的名字。
在内存中(栈里)得到的是

注意:r的内存中没有任何数据,是空对象,空对象不能使用,因为它没有任何实体。
为声明的对象分配变量
使用new运算符和类的构造方法为声明的对象分配变量,即创建对象(真正的对象,内存在堆中)。
eg r=new Rectangle();

注意:
1. 类声明的变量实际上是对象的引用变量,引用可以看作对象实体的名称,可以使用这个名称来操作对象实体的变量以及调用对象实体的方法;
2. 分配给对象(1中说明的引用)的变量(真正的对象)习惯地称做对象的实体;
3. 当用一个类用new运算符创建多个对象时,不同的对象被分配的变量占有不同的内存空间,因此,改变其中一个对象的变量不会影响其他对象的变量。
4. 一个类声明的两个对象如果有相同的引用(即值相同,这里的对象其实就是引用变量,引用变量内存放的值是对象实体的地址),那么两者具有完全相同的实体。

使用对象
对象既可以操作自己的变量改变状态,还可以调用类中的方法产生一定的行为。通过使用运算符“.",对象可以实现对自己变量的操作和方法的调用。
1. 对象操作自己的变量(对象的属性)
对象.变量;
2. 对象调用类中的方法(对象的行为)
对象.方法;
3. 体现封装: 当对象调用方法时,方法中出现的成员变量就是指分配给该对象的变量。
在使用对象时要注意:
1.避免使用空对象
没有实体的对象称为空对象,空对象不能使用,即不能让一个空对象去操作成员变量,调用成员方法产生行为。假如程序中使用了空对象,程序使用时会出现异常:NullPointerExceptation。
2.垃圾收集
Java有所谓的“垃圾收集”机制,这种机制周期地检测某个实体是否已不再被任何对象(引用)所拥有,如果发现这样的实体,就释放实体占有的内存。
3.注意区分对象和分配给对象的变量(即引用变量和对象实体,相当于C语言中的指针和变量),改变对象的值,如:改变r的值,r的指向改变了;改变对象的变量的值,如:改变r.width,此时r的指向没有变,还是指向堆内存中的那个实体,而实体里的width变量的值变了。
class Rectangle{
double width; //默认值为0.0
double length; //默认值为0.0
double f(){
return width*length;
}
}
public class Exp{
public static void main(String[] args){
Rectangle r; //声明了一个空对象,未赋值不能使用,哪怕Rectangle r=null;也不能使用,因为它没有实体
r=new Rectangle(); //为对象分配变量
r.width=9.21; //对象通过“."运算符操作变量,改变变量的值,对象没有改变,即对象的指向还是那个实体
r.length=11.8;
System.out.println("width="+r.width+"--"+"length="+r.length); //输出width=9.21--length=11.8
Rectangle r1=new Rectangle(); //又创建一个对象,r1
Rectangle r2=new Rectangle(); //又创建一个对象,r2,此时堆中有三个实体,分别由r,r1,r2指向
r=r1; //将对象r1中的引用赋给r,r的值改变了,即r的指向的实体变为r1指向的实体,而r原本指向的实体没有对象指向,无法操作
System.out.println("width="+r.width+"--"+"length="+r.length); //输出结果为width==0.0--length=0.0
}
}
对象组合
一个类的成员变量可以是Java允许的任何数据类型,因此,一个类的成员变量可以是类声明的对象,也就是说该类的对象(实体对象)就是将其他对象(引用)作为自己的组成部分。
1.关联关系
如果A类中的成员变量是用B类声明的对象(引用),那么A和B的关系是关联关系,称A关联于B或A组合了B
2.依赖关系
如果A类中某个方法的参数是用B类声明的对象或者A类中的某个方法的返回值类型为B类声明的对象,那么A和B类是依赖关系,称A依赖于B。
class C{
void f(){}
}
class B{
int m; //默认值0
double n; //默认值0.0
C c; //默认值null
}
class A{
B b; //B的对象为A类的成员变量,默认值为null
int x;
public static void main(String[] args){
A a=new A(); //a的变量有x和b,b此时为空对象
a.b=new B(); //为对象b分配变量m,n,c,其中c为C类对象,此时为空对象
}
}

实例成员和类成员
实例变量和类变量
在声明成员变量时,用关键词static修饰的称作类变量,否则称为实例变量(类变量也称为static变量,静态变量)
实例变量和类变量的区别:
1. 不同对象的实例变量互不相同,即被分配不同的内存空间
2. 所有对象共享类变量,即所有的对象的类变量占用相同的一处内存空间
3. 可以通过类名直接访问类变量,不可以通过类名访问实例变量
【当Java程序执行时,类的字节码文件被加载到内存,如果类没有创建对象,类中的实例变量是不会被分配内存,但是,类中的类变量在该类被加载到内存时就被分配了相应的内存空间。如果该类创建对象,那么不同的对象的实例变量互不相同,被分配不同的内存空间,而类变量不会重新分配内存,所有对象共享类变量,即所有的对象的类变量占用相同的一处内存空间,直到程序退出运行,类变量才释放所占有的内存。】
实例方法和类方法
在方法的声明中的类型前加static修饰的方法是类方法,不加static修饰的是实例方法。
实例方法和类方法的区别:
1. 实例方法只能用对象调用,而类方法既可通过对象调用,也可以直接用类名调用。
2. 实例方法中不仅可以操作实例变量,还可以操作类变量。当用对象调用实例方法时,该方法中出现的实例变量就是分配给该对象的实例变量;该方法中出现的类变量也是分配给该对象的变量,只不过这个变量和其他所有的对象共享,只有一份内存空间。
3. 类方法里只能操作类变量,调用类方法,而不能操作实例变量,这是因为在类创建对象之前,实例成员变量还没有被分配内存,而此时用类名直接调用类方法,类方法中操作的实例变量实际并不存在,这就出现错误。同样地不能调用实例方法,这是因为在实例方法中可能有实例变量。
【当类的字节码文件被加载到内存时,类的实例方法不会被分配入口地址,只有类创建对象后,才分配,从而实例方法可以被类创建的任何对象调用执行,方法的入口地址被所有的对象共享,也就是说,当创建了第一个对象后再创建对象时,不再分配入口地址。而当所有的对象都不存在时,方法的入口地址才被取消。
对于类方法,在该类被加载到内存时就被分配了相应的入口地址。从而类方法不仅可以被类创建的任何对象调用,还可以通过类名直接调用。类方法的入口地址直到程序退出才被取消。】
如果一个方法不需要操作任何实例变量就可以实现某种功能,就可以考虑将这样的方法声明为类方法,可以避免创建对象浪费内存空间。
静态代码块
格式:
public class 类名称{
static{
//静态代码块的内容
}
}
特点:当第一次用到该类时,静态代码块执行唯一的一次,且静态代码块总是优先于非静态内容执行,所以静态代码块比构造方法先执行。
方法重载
Java中存在两种多态:重载(Overload)和重写(Override),重写是和继承有关的多态。
【对象的功能是通过类中的方法实现的,那么功能的多态性就是方法的重载】
方法重载:一个类中可以有很多个名字相同的方法,但是这些方法的参数必须不同,即参数的个数或者参数的类型不同,与方法的返回类型无关。
this关键字
this是Java的一个关键字,表示当前对象。this可以出现在实例方法和构造方法中,但不可以出现在类方法中,这是因为类方法可以通过类名直接调用,这时可能还没有创建任何对象。
当实例变量出现在实例方法中,默认格式为:this.成员变量;
当类成员出现在实例方法中,默认格式为:类名.成员变量;
当对象调用实例方法时,方法中的实例变量就是指分配给该对象的实例变量,类变量则和其他对象共享,故通常情况,实例变量前的“this.”可以省略,而类变量前的“类名.”也可以省略。
但是,当成员变量的名字和局部变量的名字相同时,成员变量前的"this."或者"类名."就不能省略。
包
包是Java语言中有效管理类的一个机制。
包名的目的是为了有效地区分名字相同的类。不同Java源文件中的两个类名相同的类可以通过隶属不同的包来区分。
通过关键字package来声明包语句。一般格式:package 包名; 包名可以是一个合法的标识符,也可以是若干个标识符加“.”分割而成。
eg package sunrise;
package sum.com.cn;
package语句作为Java源文件的第一条语句,为该源文件中声明的类指定包名。如果源程序中省略了package语句,那么源文件中所定义的类被隐含地认为是无名包的一部分。
若干没有包名的类只要它们的字节码文件放在相同的目录下就属于同一个包。
import语句
一个类可能需要用另一个类声明的对象作为自己的成员变量或方法中的局部变量,如果这两个类在同一个包,当然没有问题。如果一个类想要使用的类和自己不在同一个包中,那么可以使用import语句。
一个源程序中可以有多个import语句,它们必须写在package语句和源文件中类的定义之间。
【如果用户需要使用类库中的类就必须使用import语句(除了java.lang包中的类,因为java.lang是Java的核心类库,它包含运行Java程序必不可少的系统类,系统会自动引入java.lang包中的类(eg System类)因此不需要import语句引入该包中的类)。使用非类库中有包名,且和当前类不在同一个包中的类也必须使用import语句。如果一个源文件中的类想使用无包名中的类,只要将这个类的字节码和当前类保存在同一目录即可】
要避免类名的混淆:
当我们在使用一个类时,只要不引起混淆就可以省略该类的包名,但是在一些特殊情况下就不能省略包名。
1. 区分无包名和有包名的类
如果一个源文件中使用了一个无名包中的一个类,同时又用import语句引入了某个有包名且同名的类,就可能引起类名的混淆。想同时使用两个类就不能省略包名。
2. 区分有包名的类
如果一个源文件引入两个包中的同名的类,那么在使用该类时,不允许省略包名。
访问权限
成员变量和方法的访问权限
当用一个类创建了一个对象之后,该对象可以通过“."运算符操作自己的成员变量和调用方法,但是对象操作自己的变量和调用方法是有一定限制的。
所谓访问权限是指对象是否可以通过“."运算符来操作自己的变量或调用方法。
访问限制修饰符有private、protected和public。(访问范围:public>protected>无修饰符>private)
【需要特别注意的是:类的实例方法中可以操作该类中的实例变量和类变量;类的类方法可以操作该类中的类变量,这些都是和访问权限无关的】
private
用private修饰的成员变量和方法称为私有变量和私有方法。
对于一个类的私有成员变量或方法,只能在该类中被访问,当我们用该个类在另一个类中创建对象时,不能通过“.”运算符来访问。面向对象编程提倡对象应当调用方法来改变自己的属性,类应当提供操作成员变量的方法,这些方法可以是经过精心设计的,使得对成员变量的操作更加合理。
public
用public修饰的成员变量和方法被称为共有变量和共有方法。
无修饰符
无修饰权限的成员变量和成员方法称为友好变量(包保护变量),友好方法,在同一个包内使用时相当于public,在包外使用相当于private。
protected
用protected修饰的成员变量和方法被称为受保护的成员变量和受保护的方法。

共有类和友好类
类声明时,在关键词class前面加上public关键词修饰,就称这样的类是一个public类,如果不加public修饰,这样的类称为友好类。
共有类和友好类的区别:
一个共有类可以被其他所有的类使用。而一个友好类想要被其他类使用时,要确保它们在同一个包中。
【不能用protected和private修饰类】
本文详细介绍了面向对象编程的核心思想,包括抽象、封装、继承和多态。重点讲解了类的声明、成员变量、方法、构造器、对象创建、参数传递方式、可变参数、访问权限以及this关键字等概念。同时,探讨了对象的生命周期、垃圾收集以及对象组合。此外,还阐述了包、import语句的作用,并讨论了访问权限控制以及实例成员和类成员的差异。通过对这些概念的理解,读者能够更好地掌握面向对象编程的基本原理。
1017

被折叠的 条评论
为什么被折叠?



