面向对象编程
类与对象
- 一个程序就是一个世界,有很多事物(对象[属性,行为])
- 类是编程人员自行定义的一种数据类型,实例化后生成对象
对象在内存中的存在形式
- 根据属性信息的数据类型的不同,选择将其存放在堆中或方法区的常量池中,如对于数据类型的String的name信息,将该属性内容存储在常量池中,而堆中则存储其地址,对于数据类型为基本数据类型的属性信息,则直接存放在堆中
对象创建的流程分析
-
class Person{ int age = 18; String name; Person(String n ,int a){ name= n; age = a; } } Person p = new Person("jack", 22);
-
流程分析
- 加载Person类信息(Person.class),只会加载一次
- 在堆中分配空间(地址)
- 完成对象初始化
- 默认初始化
- 显示初始化
- 构造器初始化
- 把对象在堆中的地址返回给p(p是对象名,或者说是对象的引用)
属性注意细节
- 属性=成员变量=field(字段)
- 属性可以是基本数据类型,也可以是引用数据类型:String、对象
- 属性的定义语法与变量定义相同:访问修饰符 属性类型 属性名
- 访问修饰符用于控制属性的访问范围,有四种:public, protected, 默认, private
- 属性如果不赋值,有默认值,规则与数组一致
- int 0,short 0, byte 0, long 0,float 0.0, double 0.0,char \u0000,boolean false,String null
类和对象的内存分配机制
-
java内存的结构分析
- 栈:一般存放基本数据类型(局部变量)
- 堆:存放对象(Cat cat,数组等)
- 方法区:常量池(常量,如字符串),类加载信息
-
java创建对象的流程分析
-
Person p1 = new Person(); p1.age = 10; p1.name = "jack";
-
先加载Person类信息(属性和方法,只会加载一次)
-
在堆中分配空间,进行默认初始化
-
把地址赋给p1,使p1指向堆中的对象
-
进行指定初始化,如p1.age = 10
-
成员方法
方法调用机制
-
注意:调用成员方法getSum时,会建立一个独立于main栈的方法栈执行方法内程序,并将结果返回给res值,后该方法栈被销毁,所占内存空间被释放
-
方法调用小结
- 当程序执行到方法时,就会开辟一个独立的空间(栈空间)
- 当方法执行完毕,或者执行到return语句时,就会返回
- 返回到调用方法的地方
- 放回后,继续执行方法后面的代码
- 当main方法(栈)执行完毕,整个程序退出
-
使用成员方法的好处
- 提高代码的复用性
- 可以将实现的细节封装起来,然后供其他的用户调用即可,便于开发
-
成员方法的定义
-
public 返回数据类型 方法名(形参列表){ 语句块; return 返回值; }
-
当返回数据类型为void时,表示该方法没有返回值,无需return语句
-
方法使用细节
-
访问修饰符
- 用于控制方法的使用范围,有四种:public, protected, 默认,private
-
返回数据类型
-
一个方法最多只能有一个返回值,但可通过设置返回数据类型为数组,来实现返回多个结果
-
public int[] getSumAndSub(int n1, int n2){ int[] resArr = new int[2]; resArr[0] = n1 + n2; resArr[1] = n1 - n2; }
-
-
返回数据类型可为任意类型:基本数据类型、引用类型
-
若方法要求有返回数据类型,则方法体中最后的执行语句必须为return 值;且要求返回值类型必须和return的值类型一致或兼容(自动类型转换)
-
如果方法为void,则方法体中可以没有return语句,或者只写return而不返回具体值
-
public void fun{ return;//正确,并未返回值 }
-
-
-
形参列表
- 一个方法可有0个或多个参数,中间用逗号隔开
- 参数类型可以为任意类型:基本数据类型、引用类型
- 调用带参数的方法时,一定要根据参数列表传入相同类型或兼容类型的参数
- 方法定义时的参数称为形式参数,即形参;方法调用时传入的参数成为实际参数,即实参,实参和形参的类型要一致或兼容,个数、顺序必须一致
-
方法体
- 方法体中不可再定义方法,即方法不可以嵌套定义
-
方法调用细节说明
- 同一个类中的方法可以直接调用
- 跨类中的A类方法调用B类方法,需要先实例化一个B类对象,再进行B类方法的调用
- 跨类的方法调用和方法的访问修饰符相关,如某类的private方法不可被其他类调用
方法传参机制
-
基本数据类型的传参机制
-
基本数据类型传参传的是值(值拷贝),形参的任何改变不影响实参
-
public void swap(int num1,int num2){ System.out.println("交换前num1=" + num1 + " num2=" + num2); int temp = num1; num1 = num2; num2 = temp; System.out.println("交换后num1=" + num1 + " num2=" + num2); }
-
当main程序调用该方法时,会开辟一个独立于main栈的方法栈空间,并将参数值拷贝给形参,后续值的交换在方法栈中进行,方法执行完成后返回main栈,且main栈中的实参值不被改变
-
-
引用数据类型的传参机制
- 引用数据类型传递的是地址,可以通过形参影响实参
- 被调用方法中形参和main栈中的实参指向的是同一内存空间,因此当在方法中执行更改该空间中内容语句时,main栈中的实参指向的内容也会发生改变
递归
- 自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂问题,同时让代码变得简洁
递归执行机制
-
递归递归,先递后归
-
递归重要规则
- 执行一个方法时,就创建一个新的受保护的独立空间
- 方法的局部变量是独立的,不会相互影响
- 若方法中使用的是引用类型变量(如数组、对象等),就会共享该引用类型的数据
- 递归必须向退出递归的条件逼近,否则就会无限递归
- 当一个方法执行完毕,或者遇到return,就会返回,遵守谁调用,就把结果返回给谁;同时,该方法执行完毕或返回后,所占栈空间释放
方法重载overload
- java中允许同一个类中有多个同名方法,但要求形参列表不同,如
System.out.println();//out是PrintStream类型
- 重载的好处
- 减轻了起名的麻烦
- 减轻了记名的麻烦
重载使用细节
-
方法名必须相同
-
形参列表必须不同,即参数类型、个数和顺序至少要有一样不同
-
返回类型:无要求,如以下两方法并未构成重载,编译会报错
-
public int calculate(int n1, int n2){ return n1 + n2; } //该方法和上面方法并未构成重载 public void calculate(int n1, int n2){ System.out.println(n1 + n2); }
-
可变参数
- Java允许将同一个类中多个同名同功能但参数个数不同de方法,封装成一个方法,就可以通过可变参数实现
- 基本语法
- 访问修饰符 返回类型 方法名(数据类型… 形参名){…}
可变参数细节
- 可变参数的实参可以为数组
- 可变参数可以和普通类型的参数一起放在形参列表,但必须保证可变参数在最后
public void f1(String s1, double...nums){...}
- 一个形参列表只能出现一个可变参数
public int sum(String s, int...nums1,double...nums2){}//错误
作用域
- Java编程中,主要变量就是属性(成员变量)和局部变量
- 局部变量一般是指在成员方法中定义的变量
- 全局变量:也就是属性,其作用域为整个类体
- 局部变量:除了属性之外的其他变量,作用域为定义它的代码块
- 全局变量可以不赋值就可以使用,因其有默认值,局部变量必须先赋值再使用
作用域使用细节
- 属性和局部变量可以重名,访问时遵循就近原则
- 同一个作用域,如同一个成员方法中,两个局部变量不能重名
- 属性生命周期比较长,伴随着对象的创建而创建,伴随着对象的销毁而销毁;局部变量的生命周期较短,伴随着定义它的代码块的执行而创建,伴随着代码块执行结束而死亡
- 作用域范围不同:
- 全局变量/属性:可以被本类使用,也可被其他类使用(通过创建对象,调用属性)
- 局部变量:只能在本类中对应的方法调用
- 修饰符不同:
- 全局变量/属性可以加访问修饰符
- 局部变量不可加
构造方法/构造器
-
constructor,是类的一种特殊方法,作用是完成对新对象的初始化
-
在创建对象时,系统会自动调用该类的构造器来完成对象的初始化
-
基本语法
-
[修饰符] 方法名(形参列表){ 方法体; }
-
-
修饰符可为default, public, protected, private
-
构造器没有返回值,也不能写void
-
构造器要和类名相同
-
参数列表和成员方法一样的规则
-
构造器的调用,由系统完成
构造器使用细节
- 一个类可以定义多个构造器,即构造器重载,形参列表要不同
- 若程序员没有定义构造器,系统会自动给类生成一个默认无参的构造方法(默认构造方法),如Person(){}
- 一旦定义了自己的构造器,默认的构造器就覆盖了,不能再使用默认的无参构造器,除非显式的定义一下,如Dog(){}
this关键字
- Java虚拟机会给每个对象分配this,代表当前对象
this使用细节
- this关键字可以用来访问本类的属性、方法、构造器
- this用于区分当前类的属性和局部变量
- 访问成员方法的语法:this.方法名(参数列表)
- 访问构造器语法:this(参数列表),只能在构造器中通过this关键字访问另一个构造器,且this语句必须放在第一句
- this不能在类定义的外部使用,只能在类定义的方法中使用
如Dog(){}
this关键字
- Java虚拟机会给每个对象分配this,代表当前对象
this使用细节
- this关键字可以用来访问本类的属性、方法、构造器
- this用于区分当前类的属性和局部变量
- 访问成员方法的语法:this.方法名(参数列表)
- 访问构造器语法:this(参数列表),只能在构造器中通过this关键字访问另一个构造器,且this语句必须放在第一句
- this不能在类定义的外部使用,只能在类定义的方法中使用