类和对象
类的语法格式
类的语法格式为:
修饰符 class 类名{
语句;
}
例如建立一个Person类:
public class Person {
String name = "Tom";
int age = 18;
public void show(){
System.out.println(name+"已经"+age+"岁");
}
}
类的五大成员:属性、方法、构造器、代码块、内部类
对象的语法格式
建立类的实例——对象,格式如下:
类名 对象名 = new 对象名(参数列表);
如建立Person类的实例:
Person person = new Person();
匿名对象
对于只需进行一次方法调用的对象,无需为它分配一个引用存储到虚拟机栈,这时需采用匿名对象,格式如下:
new 对象名(参数列表).方法名(参数列表);
例如创建Person的匿名对象,调用其中一个方法:
new Person().show();
类和对象内存说明
- java虚拟机的虚拟内存空间分为方法区、本地方法栈、虚拟机栈、堆、程序计数器。
- 方法区存储的内容包括:被虚拟机加载到类、常量、静态(static)变量、即时编译器编译后的代码,所以类存储于方法区;
- 虚拟机栈主要用于存储局部变量,对象调用方法时,方法体内的局部变量加载到虚拟机栈,方法执行完后自动释放相应局部变量。
- 堆用于存放对象实例,所有对象实例和数组都要在堆分配内存。
- 所以对象在创建时,堆内存开辟一块区域存储对象,对象的引用则存储在虚拟机栈的一个变量中。
- 对象的属性(非静态)由于在堆内存,所以会自动初始化为默认值,对象的方法(非静态)也存储于堆内存。
- 调用的时候,方法的局部变量加载到虚拟机栈运行。
属性
属性(又称域、字段、filed、成员变量等),声明于类的体内,如上面Person类的name和age属性,声明格式为:
修饰符 数据类型 变量名 = 初始化值; //也可默认初始化
属性与局部变量的区别
- 声明的位置:成员变量(属性) 类体内;局部变量 方法体或形参、代码块内、构造器等。
- 修饰符:成员变量(属性) 可被public,private,protect,final,static等修饰;局部变量只能被final修饰。
- 初始化:成员变量有默认初始化值,局部变量必须被无默认初始化值,必须被显式赋值才能使用。
- 存储位置:前者堆或方法区的静态域;后者虚拟机栈。
方法
Java里的方法用于实现类或对象的某个功能或操作,可理解为“函数”或“过程”,Java中方法只能存在于类或对象中,不能独立存在。方法声明的格式为:
修饰符 返回值类型 方法名(形参列表){方法体语句;}
例子见上面Person对象的show()方法。
注意:
- 不能在方法内部调用方法;
- 无返回值的方法可以利用return;来结束方法;
方法重载
重载:在同一个类中,允许出现多个同名的方法,只要他们参数列表不同,即可构成重载。
注意:
- 参数列表不同体现为:参数数量不同、参数类型不同、参数顺序不同等;
- 重载只取决于参数列表,与方法的修饰符、返回值类型无关;
- JDK5.0之后,可以采用可变形参的方法传递同一类型的参数,其等效于传递一个数组,如void test(int a, char …b){;},其传入的第一个实参为int型,后续若干实参均为char型,且后续的char型实参个数可为0、1或多个,该方式等效于void test(int x, char[] b){;},二者不能构成重载。
例如:
public void test1(int a, String b, char c, char d){;} //原方法
private int test1(int a, String b, char c, char d){;} //方法1
public void test1(int a, String b, char d, char c){;} //方法2
double test1(){;} //方法3
private double test1(char x,int...a){;} //方法4
protected void test1(char y,int[] a){;} //方法5
上述代码,方法1、2不与原方法构成重载;方法3、4、5均与原方法构成重载,其中方法4与方法5不构成重载。
方法的参数值传递机制
方法由类或对象调用,对于有参的方法,其声明时的参数称为形参,其被调用时传入的参数称为实参。
方法在调用时,实参内容(基本类型的值或对象的引用)复制给方法内的形参,供运行于虚拟机栈的方法使用。
递归
例1:斐波那契数列问题1,1,2,3,5,8,13,21,34,55,求第n项
public class Feibonaci {
public static void main(String[] args) {
for (int i=0; i<10; i++)
System.out.println(feibonaci(i));
}
private static int feibonaci(int n) {
if (n==1||n==2){
return 1;
}else if(n>2){
return feibonaci(--n)+feibonaci(--n);
}else{
return -1;
}
}
}
例2:汉诺塔问题。在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置64个金盘。目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上。如下图。
写程序计算完成任务需要移动多少次,代码如下:
public class Hanoi {
public static void main(String[] args) {
System.out.println(hanoi(20));
}
private static long hanoi(int num) {
if (num==1){
return 1L;
}else if(num>1){
//System.out.println(num);
return 2L*hanoi(--num)+1L;
}else{
return -10;
}
}
}
上述代码运行结果为:当有20块盘子,需搬运1048575次
构造器
构造器是类的重要成员,它用于创建对象,构造器的形式为:
修饰符 类名(参数列表){语句;}
- 如果自定义类没写构造器,则创建对象时,会自动提供一个默认构造器,默认构造器为空参,且修饰符与所属类一致;
- 如果自定义类定义了空参构造器,则创建对象时直接可以使用该空参构造器;
- 如果只声明了若干带参构造器而没定义空参构造器,则无法创建不带参的对象;
- 带参构造器可以让创建实例时进行初始化;
- Java中,每个类至少要有一个构造器,子类不能继承父类的构造器;
给Person类写三个重载构造器代码如下:
public class Person {
public String name = "Tom";
public int age = 18;
//空参构造器
public Person(){
System.out.println("空参构造器");
}
//带参构造器
public Person(String name){
this();
this.name = name;
System.out.println("带参构造器1");
}
//带参构造器
public Person(int age){
this("Carray");
this.age = age;
System.out.println("带参构造器2");
}
//带参构造器
public Person(String name,int age){
this(age);
this.name = name;
this.age = age;
System.out.println("带参构造器3");
}
public void show(){
System.out.println(name+"已经"+age+"岁");
}
}
Person p1 = new Person(23); //创建时把age初始化
Person p2 = new Person("Tom"); //创建时初始化name
Person p3 = new Person("Tom",23); //创建时初始化age和name
this关键字
- this关键字用于调用类和对象的属性,方法和构造器;
- 方法体中的this表示调用该方法的类或对象,构造器中的this表示该构造器初始化的对象;
- 在方法或构造器内使用成员变量或成员方法时,均可加上this.以增强可读性,但一般不写,当需要区分形参变量与成员便是,就必须写;
- this访问的属性或方法如果在当前类找不到,可以从父类中寻找;
- this可以用于一个类中构造器相互调用,一个构造器只能在第一行调用其他构造器,且只能调用一次其他构造器;
this使用的例子见上面Person类代码,建立上述Person类的一个实例:
public class ThePerson1 {
@Test
public void Test2(){
Person p4 = new Person("Tom",23);
System.out.println("------------------------------------------");
System.out.println(p4.name+p4.age);
}
}
运行结果为:
封装性
程序设计追求高内聚(类的内部操作细节由自己完成,不允许外部干涉),低耦合(仅对外部暴露少数用于使用的方法)。
封装性程序设计思想在于:隐藏对象内部的复杂性,仅对外部提供简单的接口,便于外部调用,有利于提高扩展性和维护性。
对类的属性用private修饰符隐藏起来,避免用户直接操作属性,而是提供setter和getter的方法简介设置和获取属性。
Java有4种权限修饰符用于修饰属性、方法或类的访问权限:private、缺省、protected、public,权限大小如下图: