Java中的类和C中的结构体相似,并且类中可以包含方法和变量。
而对象就好比C中的结构体变量,对象通过‘.’来调用类中的方法和变量。
以上是我的个人理解,下面来具体说说类和对象。
类
类是组成Java源文件的基本元素一个源文件是由若干个类组成的。
类的形式如下:
class 类名{
类体
}
class是关键字,用来定义类,类名命名时每个单词的首字母大写,类体包含变量的声明和方法的定义。
变量
一个类可以包含以下类型变量:
- 局部变量:在方法、构造方法或者语句块中定义的变量被称为局部变量。变量声明和初始化都是在方法中,方法结束后,变量就会自动销毁。
- 成员变量:成员变量是定义在类中,方法体之外的变量。这种变量在创建对象的时候实例化。成员变量可以被类中方法、构造方法和特定类的语句块访问。
- 类变量:类变量也声明在类中,方法体之外,但必须声明为static类型。
不能在方法之外对成员变量进行任何操作,当局部变量和成员变量同名时,成员变量会暂时失效。
其中类变量为所有由该类的所有对象所共享,不同对象的实例变量互不相同。
方法
方法更像c中的函数,只是叫法不同。
构造方法
每个类都有构造方法。如果没有显式地为类定义构造方法,Java编译器将会为该类提供一个默认构造方法。
在创建一个对象的时候,至少要调用一个构造方法。构造方法的名称必须与类同名,一个类可以有多个构造方法。
下面是一个构造方法示例:
public class Puppy{
public Puppy(){
}
public Puppy(String name){
// 这个构造器仅有一个参数:name
}
}
和c不同的是,方法名可以相同,但是方法中的参数类型不能相同,如:
class Ar{
void pa(int a,char b){
}
void pa(char a,int b){
}
int pa(int a){
}
}
这样写是合法的,调用时Java根据方法名+参数来确定由哪个方法执行。
同样的,方法也分为类方法和实例方法,定义类方法要在前面加static关键字。
实例方法既可以操作实例变量也可以操作类变量,当对象调用实例方法时,方法中的成员变量就是分配给该对象的成员变量。
类方法只能操作类变量,当对象调用类方法时方法中的成员变量一定都是类变量。
类之间的关系
- 依赖(uses-a)
依赖(dependence),即“uses-a”关系,是一种最明显的、最常见的关系。依赖关系表现为一个类(A)的方法操作了另外一个类(B)的对象,我们就说类A依赖于类B。
应该尽可能地将相互依赖的类减至最少。如果类A不知道B的存在,那么B的变化对A就没有影响。这就是类之间的低耦合。
- 聚合(has-a)
聚合(aggregation),即“has-a”关系,是一种具体且易于理解的关系。聚合的表现为A的对象包含B的对象。
- 继承(is-a)
继承(inheritance),即“is-a”关系,是一种用来表示特殊与一般的关系。
源文件声明规则
当在一个源文件中定义多个类,并且还有import语句和package语句时,要特别注意这些规则。
- 一个源文件中只能有一个public类
- 一个源文件可以有多个非public类
- 源文件的名称应该和public类的类名保持一致。例如:源文件中public类的类名是Employee,那么源文件应该命名为Employee.java。
- 如果一个类定义在某个包中,那么package语句应该在源文件的首行。
- 如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面。
- import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
类有若干种访问级别,并且类也分不同的类型:抽象类和final类等。这些将在访问控制章节介绍。
除了上面提到的几种类型,Java还有一些特殊的类,如:内部类、匿名类。
需要注意的问题
对成员变量的操作只能放在方法中,如:
class A{
int a=12;
char b='x';
}
不可以这样写,如:
class A{
int a;
char b;
a=12; //错误
b='x'; //错误
}
对于成员变量的操作只能在方法中进行,如:
class A{
int a;
char b;
void e{
int c;
c=10;
a=12;
b='x';
}
}
对象
类声明的变量称为对象,相当于C语言的结构体变量,对象既可以调用类中的变量也可以调用类中的方法。
People zhangsan = new People(); //声明一个对象,其中People为类名,zhangsan为对象名,
//People()为Java默认的构造方法。
或
People zhangsan;
zhangsan = new People();
构造方法也可以自己定义,如:
class People{
int age;
People(int age){ //构造方法名和类名相同,一个类可以有多个构造方法,在之前的讲的方法中写过
this.age = age;
}
}
People zhangsan = new People(20); //zhangsan.age=20
People zhangjiu = new People(25); //zhangjiu.age=25
this
其中,this为关键字,表示某个对象,可以出现在实例方法和构造方法中,但不可以出现在类方法中,this出现在类的构造方法中时,代表使用该构造方法所创建的对象。this出现在实例方法中,代表正在调用该方法的当前对象。
如果类中定义了构造方法,那么Java不提供默认的构造方法,所以下面的写法是错误的,
class People{
int age;
People(int age){ //构造方法名和类名相同,一个类可以有多个构造方法
this.age = age;
}
}
People zhangsan = new People(20); //zhangsan.age=20
People zhangjiu = new People(); //非法
对象、数组、接口都属于引用类型,好比C中的指针。
class Point{
int x;
int y;
Point(int x,int y){
this.x=x;
this.y=y;
}
}
Point p1 = new Point(12,16); //p1.x=12,p1.y=16
Point p2 = new Point(6,18); //p2.x=6,p2.y=18
p1 = p2; // p1.x=6,p1.y=18,p2.x=6,p2.y=18
内存模型如下
由于p1=p2操作,系统将取消原来分配给p1的内存,这时候p1和p2实际上指向的是同一片内存区域,改变p1或p2中的一个,另一个也相应改变。
Java包
包主要用来对类和接口进行分类。就好比树状文件夹,当开发Java程序时,可能编写成百上千的类,因此很有必要对类和接口进行分类。
Import语句
在Java中,如果给出一个完整的限定名,包括包名、类名,那么Java编译器就可以很容易地定位到源代码或者类。Import语句就是用来提供一个合理的路径,使得编译器可以找到某个类。