JavaSe基础:面向对象1
1. 面向对象
对象(object)是具体的实物,类(class)是对对象的抽象,类可以看做是一个模版,或者图纸,系统根据类的定义来造出对象。
1.1 类的定义方式
类的定义方式如下:
class 类名{
}
在类中可以定义成员变量:
[修饰符] 属性类型 属性名 [= 默认值] ;
也可以定义方法:
[修饰符] 方法返回值类型 方法名(形参列表) {
方法体;
}
1.2 对象的创建和使用
根据类可以创建对象,必须使用new关键字创建对象。
类名 对象名 = new 类名();
创建的对象可以使用类中的成员变量,使用 对象名.成员变量名。
同时也可以调用类中的方法,语法如下:
对象名.方法名();
例:
public class CarTest{
public static void main(String[] args){
//创建一个对象c1
Car c1 = new Car();
//调用成员变量
c1.brand = "奥迪";
c1.paiLiang = 2.0;
c1.price = 250000;
System.out.println(c1.brand);
System.out.println(c1.paiLiang);
System.out.println(c1.price);
//调用成员方法
c1.run();
}
}
//定义汽车类
class Car{
//定义成员变量
public String brand;
public double paiLiang;
public int price;
//定义成员方法
public void run(){
System.out.println("跑起来了!!");
}
}
2. 内存分析
Java中创建新对象会有内存方面的了解过程,内存分为以下三种:
-
栈:调用方法时压栈执行,方法执行完毕弹栈释放内存
栈中数据的特点:先进后出,后进先出,执行完毕马上弹栈释放内存,储存方法执行中产生的数据
-
堆:以地址的形式存放新建的对象及其成员变量
堆中数据的特点:数据无序,根据对象数据的地址区别数据,垃圾回收机制定时定点清理
-
方法区:存放加载的类及方法
具体用下面的代码进行说明:
public class Student {
public String name;
public int age;
public String hoppy;
public void study(){
System.out.println(name+"正在学习中...");
}
}
public class StudentTest {
public static void main(String[] args) {
//新建对象stu1
Student stu1 = new Student();
stu1.name = "张三";
stu1.age = 20;
stu1.hoppy = "打篮球";
stu1.study();
//新建对象stu2
Student stu2 = new Student();
stu2.name = "李四";
stu2.age = 25;
stu2.hoppy = "踢足球";
stu2.study();
}
}
内存分析图如下所示:
内存分析:
-
将Student.class,StudentTest.class加载到方法区
-
执行StudentTest类中的main方法,由JVM调用压栈执行,在栈中为主方法开辟栈帧
-
逐行执行main方法中的代码
-
new Student()创建Student类型的对象stu1
注:new关键字的作用是:
- 在堆中为对象开辟内存空间,成员变量跟随对象进入到堆内存,并附默认值
- 调用构造器为对象初始化信息
- 将对象的地址返回给引用
-
将堆内存中对象的地址(假设是0x001)赋值给引用stu1,stu1引用指向堆内存中的这个对象,stu1变量中存储该对象的地址值,stu1引用代表这个对象,根据stu1变量名使用该对象
-
stu1.name代表对象地址中的name属性,赋值为"张三";stu1.age代表对象地址中的age属性,赋值为20;stu1.hoppy代表对象地址中的hoppy属性,赋值为"打篮球"
-
调用stu1对象的study()方法,压栈执行,在栈中为其开辟栈帧
-
执行study()方法中的代码,输出内容,在成员方法中的成员变量到调用方法的对象的内存空间里去找,0x001的内存空间中,name属性值为"张三",输出结果是"张三正在学习中…"
-
study()方法执行完毕,弹栈释放内存
-
main方法继续往下执行,new Student()创建Student类型的对象stu2,其他的操作如上述第5步到第9步
-
主方法执行完毕,弹栈释放内存,程序执行完毕
3. 构造器
构造器(也叫构造函数或者构造方法)是一个特殊的方法,用来为对象初始化信息(为成员变量赋值),跟随new关键字使用,定义方式如下:
修饰符 类名(参数列表){
...
}
不需要返回值类型也不需要void,可以使用return关键字也可以不使用。
注:
- 如果没有显示定义的构造器,编译器会自动提供一个空构造(没有参数)
- 如果存在显示定义的构造器,编译器不会再提供任何构造器了
- 构造器是特殊的方法,可以构成方法的重载即构造器的重载
- 构造器不是用来创建对象的,是用来为对象初始化信息的
- 可以通过构造器使用创建对象的同时赋值,简化代码结构
- 自定义的类至少提供一个空构造,根据需求提供是否带参
例:
public class ConstructorTest {
public static void main(String[] args) {
//使用无参构造器创建对象
Dog dog1 = new Dog();
dog1.bark();
//使用有参构造器创建对象
Dog dog2 = new Dog("大黄","柴犬",10);
dog2.bark();
}
}
//定义dog类
class Dog{
//定义成员变量
public String name;
public String type;
public int age;
//无参构造器
public Dog(){
System.out.println("空构造");
}
//有参构造器
public Dog(String dogName,String dogType,int dogAge){
name = dogName;
type = dogType;
age = dogAge;
System.out.println("有参构造");
}
//定义成员方法
public void bark(){
System.out.println("一条叫"+name+"的"+type+"品种的"+age+"岁的狗正在叫");
}
}
4. this关键字
this关键字指代当前对象(即new的对象),有两种使用方式:
- 在构造器的首行,通过this(实参)调用本类中的其他构造器
例:
public class Test01 {
//无参构造器
public Test01(){
//调用本类中的其他构造器
this(false);
System.out.println("空构造");
}
//有参构造器
public ThisDemo(boolean flag){
System.out.println("一个boolean类型参数构造器"+flag);
}
//主方法
public static void main(String[] args) {
//创建对象
Test01 test = new Test01();
}
- 区分同名变量问题即局部变量与成员变量之间的同名问题,默认是就近原则
- 在构造器中方法内部的自定义局部变量与成员变量同名时,使用 “this.变量名” 代表成员变量,this指代当前new的对象
- 在方法中局部变量与成员变量同名时,使用 “this.变量名” 代表成员变量,在成员方法中this指代调用成员方法的对象,当没有同名问题的时候,指代成员时默认省略this.
例:
public class ThisTest {
public static void main(String[] args) {
//创建对象
Cat cat1 = new Cat("小白","布偶猫");
cat1.catchMouse();
//创建对象
Cat cat2 = new Cat("小黑");
cat2.catchMouse();
}
}
//定义类
class Cat{
String name;
String type;
//无参构造器
public Cat(){}
//有参构造器
public Cat(String name){
//使用this关键字将局部变量赋值给成员变量
this.name = name;
}
//有参构造器
public Cat(String name,String type){
//使用this关键字将局部变量赋值给成员变量
this.name = name;
this.type = type;
}
//定义方法
public void catchMouse(){
System.out.println(name+type+"正在捉老鼠");
}
}
注:不要在构造器之间互相调用,可能造成死循环。成员是属于对象的,需要跟随对象才能使用,包括成员变量和成员方法。