类是面向对象的重要内容,可以把类当成一种自定义类型,可以使用类来定义变量,这种类型的变量通称为引用变量。
学习Java的345
三大引用类型:对象、接口、数组
四大修饰符:public|private|protected、final|abstract、static
类的五大主体:成员变量(field)、方法(method)、构造器(constructor)、内部类、初始化模块
一、定义类
类(class)是某一批对象的抽象,可以把类理解成某种概念。
对象(object也称为实例)是类的实例,是一个具体存在的实体。
Java定义类的基本语法如下:
1 [修饰符] class 类名 2 { 3 类的成员变量(field) 4 类的方法定义(Method) 5 类的构造器(constructor) 6 内部类 7 初始化模块 8 }
修饰符:可以是public、final|abstract,有且仅有,也可以完全省略。
类名:满足标识符的命名规则即可。从专业角度来看,有多个有意义的单词组成,其中每个单词的首字母大写
对于一个类包含5大成员:类的成员变量、方法、构造器、内部类、初始化模块。其中最常见的是成员变量、方法、构造器。如果一个成员也没有,就是一个空类,没有多大的实际意义。
成员变量(由英文单词field意译而来)
成员变量用于定义该类或该实例所包含的状态数据。定义成员变量的语法格式:
1 [修饰符] 类型 成员变量名[=默认值];
修饰符:修饰符可以省略,也可以是(public|private|protected)、static、final,public|private|protected三个只能出现一个,可以与static、final组合起来修饰成员变量。
类型:包括基本类型和引用类型
成员变量名:只要是一个合法的标识符即可。专业角度采用驼峰写法——首字母小写,后面每个单词首字母大写。
默认值:定义成员变量还可以指定一个可选的默认值。
方法
用于定义该类或该类的实例的行为特征或功能实现
定义方法的语法格式:
1 [修饰符] 方法返回值类型 方法名(形参列表) 2 { 3 //由零条到多条可执行语句组成的方法体 4 }
修饰符:5大修饰符,public|private|proteced、static、final|abstract,修饰符可以省略
方法返回值类型:返回值的类型可以是Java语言运行的任何数据类型,包括基本类型和引用类型;如果声明了方法返回值类型,则方法体内必须含有一个return语句,该语句返回一个变量或一个表达式,这个变量或表达式的类型必须与此处声明的类型匹配。
方法名:命名规则与成员变量的规则相同
形参列表:形参列表用于定义该方法可以接受的参数,形参列表由零组到多组“参数类型 形参名”组合而成,多参数之间以逗号(,)隔开,形参类型和形参名之间以空格隔开。
注意:static是一个特殊的关键字,它可以修饰成员变量、方法等成员。static修饰的成员表示它属于这个类本身,而不属于类的单个实例,因此通常把static修饰的成员变量和方法称为类变量(静态变量)和类方法(静态方法);不使用static修饰的普通方法、成员变量则属于该类的单个实例,而不属于该类。因此通常把不使用static的成员变量和方法称为实例变量(非静态变量)和实例方法(非静态方法)。
构造器
构造器是创建一个类的根本途径,如果类没有构造器,这个类就无法创建实例。因此,Java语言提供了一个功能:如果程序员没有为一个类编写构造器,则系统会为该类提供一个默认的构造器。一旦程序员为一个类提供了构造器,系统将不再为该类提供构造器。
构造器的语法格式:
1 [修饰符] 构造器名(形参列表) 2 { 3 //由零条或多条可执行语句组成构造器体 4 }
修饰符:可以是public、protected、private之一
构造器名:构造器名必须与类名相同
形参列表:和方法定义形参列表相同。
注意:构造器不能定义返回值类型,也不能使用void声明构造器没有返回值。如果为构造器定义了返回值类型,或使用void声明构造器没有返回值,编译不会出错,但是Java会将这个构造器当成方法处理。
实际上构造器是有返回值的,当使用new关键字来调用构造器时,构造器返回该类的实例,可以把这个实例当成构造器的返回值类型,因此构造器的返回值类型总是当前类,无需定义返回值类型。但注意不要在构造器里显示使用return来返回当前类的对象,因为构造器的返回值是隐式的。
定义一个类:
1 class Person 2 { 3 //定义成员变量 4 public int age; 5 public String name; 6 //age=20;这不是一个类,这是一个赋值语句,不属于类的五大成员 7 //定义一个say方法 8 public void say(String content) 9 { 10 System.out.println(content); 11 } 12 }
二、类的产生和引用以及引用与指针
创建对象的根本途径就是构造器,通过new关键字来调用某个类的构造器可创建这个类的实例。(如果没有定义构造器、系统会为该类提供一个默认的构造器)。
类是一类对象的抽象,对象是类的实体。
类的可以做什么:
(1)定义变量:所有类都是引用类型,都可以用于声明变量。
(2)调用类变量和类方法(static修饰的变量和static修饰的方法)。
(2)创建对象。new 构造器 (参数列表)——构造器名必须与类名一致
对象可以做什么?
(1)调用对象的实例变量(无static修饰的变量)
(2)调用对象的方法(无static修饰的方法)
如果访问权限允许,类里定义的变量和方法都可以通过类或实例来调用。static修饰的成员变量和方法,既可以通过类来调用,也可以通过实例来调用;没有static修饰的普通方法和成员变量,只能通过实例来调用。
类的成员变量或方法调用语句:
类.类变量|类方法
实例:定义一个Person类
1 public class Person 2 { 3 //定义成员变量 4 public String name; 5 public int age; 6 static int MAXNUM=20;//这是一个类变量 7 8 //这是一个类方法 9 static public void walk() 10 { 11 System.out.println("没病走两步"); 12 } 13 14 //下面定义一个say方法 15 public void say(String content) 16 { 17 System.out.println(content); 18 } 19 }
通过new关键字来调用Person类的构造器,来返回该类的实例。
1 class Classuse 2 { 3 public static void main(String[] args) 4 { 5 //定义一个Person类型的变量 6 //Person p; 7 //通过new关键字调用Person类的构造器,返回一个Person实例 8 //p=new Person(); 9 //上面两行代码也可以用一行代替 10 var p=new Person(); 11 12 //调用类方法可以用对象去调用,也可以使用类调用 13 System.out.println(Person.MAXNUM); 14 System.out.println(p.MAXNUM); 15 16 //普通成员变量只能通过对象来调用 17 p.say("这是一个普通方法(对象的方法)"); 18 19 /* 20 *Person.say("通过类调用"); 21 *Classuse.java:18: 错误: 无法从静态上下文中引用非静态 方法 say(String) 22 */ 23 24 Person.walk(); 25 p.walk(); 26 } 27 }
首先var p=new Person();实际上产生了两个东西,一个是p变量,一个是Person对象
类也是一种引用数据类型,因此定义Person类型的变量实际上是一个引用,它被放在栈(stack)内存中,指向实际的Person对象;而真正的Person对象则放在堆内存(heap)中。栈内存里的引用变量并未真正存储对象的成员变量,对象的成员变量实际存储在堆内存中;而引用变量的只是指向该堆内存里的对象。实际上Java的引用就是C语言的指针,只是Java把这个指针封装起来,避免了开发者进行繁琐的指针操作。
Java程序不允许直接访问堆内存中的对象,只能过该对象的引用来操作该对象。
堆内存中的对象可以由,多个引用,即多个引用指向同一个对象,代码如下:
var p1=p;
如果堆内存中的对象没有任何引用指向该对象,那么程序无法访问该对象,该对象也就变成垃圾,Java的垃圾回收器将回收该对象,释放该对象所占的内存区。因此希望通知垃圾回收器回收某个对象,可以将该对象的引用变量赋值为null。
三、对象this引用
this关键字总是指向调用该方法的对象。根据this出现的位置不同,this作为对象的默认引用有两种情形。
1、在非static修饰的方法中,this代表方法的调用者。
this关键字最大的作用是让类中的一个方法,访问该类里的另一个方法或实例变量。
1 class Dog 2 { 3 public String color; 4 public void bark() 5 { 6 System.out.println("汪!汪!汪!"); 7 } 8 9 //定义一个run方法,在run()方法中需要调用bark()方法 10 public void run() 11 { 12 System.out.println("小狗狗正在跑~"); 13 this.bark(); 14 } 15 }
在DogTest.java中调用Dog类中的方法。
1 class DogTest 2 { 3 public static void main(String[] args) 4 { 5 //创建dog对象 6 Dog d=new Dog(); 7 //调用run()方法,此时run()方法的this代表Dog对象d 8 d.run(); 9 } 10 } 11 ---------- 运行Java捕获输出窗 ---------- 12 小狗狗正在跑~ 13 汪!汪!汪! 14 15 输出完成 (耗时 0 秒) - 正常终止
this可以代表任何对象,当this出现在某个方法体中,它所代表的对象是不确定的,但它的类型是确定的;它所代表的只能是当前类的实例;只有当该方法调用时,它所代表的对象才被确定下来。谁在调用这个方法,this就代表谁。
这种用法符合实际情形:当一个Dog对象调用run()方法时,run()方法需要依赖它自己的bark()方法。通常Java一个成员调用另外一个成员时,this可以省略。上面的this.bark();可以用bark();代替。
注意:对于static修饰的方法而言,则可以使用类来直接调用该方法,如果在static修饰的方法中使用this关键字,则这个关键字无法指向合适的对象。所以说,static修饰的方法中不能使用this引用。由于static修饰的方法不能使用this引用,所以static修饰的方法不能访问不使用static修饰的普通成员,因此Java规定:静态成员不能直接访问非静态成员。一般来说,如果调用static修饰的成员时省略了前面的主调,那么默认使用该类作为主调;如果调用没有static修饰的成员时省略了前面的主调,那么默认使用this作为主调。
下面演示静态方法直接访问非静态方法时引发的错误。
class StaticToNonstatic { //定义一个普通类 public void info() { System.out.println("测试info方法"); } //main方法是一个静态方法 public static void main(String[] args) { //调用main方法的是StaticToNonstatic类,而不是该类的实例 //而info方法是一个非静态方法,只能通过实例调用 //this.info();或 info(); } } ---------- 编译Java ---------- StaticToNonstatic.java:15: 错误: 无法从静态上下文中引用非静态 方法 info() info(); ^ 1 个错误 输出完成 (耗时 1 秒) - 正常终止
大部分时候,普通方法访问其他方法、成员变量时无需使用this前缀,但如果方法中有个局部变量与成员变量同名,但程序又需要访问这个被覆盖了的局部变量,则必须使用this前缀。
2、出现在构造器中引用正在初始化的对象。
this引用也可以用与构造器中作为默认引用,由于构造器中直接使用new关键字来调用,而不是使用对象来调用的,所以this在构造器中代表该构造器正在初始化的对象。
大部分时候,在构造器中访问其他方法、成员变量时无需使用this前缀,但如果构造器中有个局部变量与成员变量同名,但程序又需要访问这个局部变量,则必须使用this前缀。
1 public int foo; 2 3 //构造器必须与类名相同 4 public ThisConstructor() 5 { 6 //在构造器中定义一个局部变量foo 7 int foo=1; 8 //在构造器中对成员变量初始化为10 9 this.foo=10; 10 } 11 12 public static void main(String[] args) 13 { 14 var p=new ThisConstructor(); 15 //此时构造器中的this代表对象p 16 System.out.println(p.foo); 17 } 18 } 19 ---------- 运行Java捕获输出窗 ---------- 20 10 21 22 输出完成 (耗时 0 秒) - 正常终止