面向对象三大主线
- 类及类的成员
- 三大特性
- 其他关键字
一、类和类的成员
类和对象
类
-
类就好像是一个模子(模版),利用属性和方法来描述对象的信息,具有某些共同特征的实体的集合,是一种抽象的数据类型.
-
类的定义方法:
修饰符 class 类名{
属性声明;
方法声明;
}
例如:
public class Person{
//属性声明
private String name;
private int age;
//方法
public void setAge(int i){
age = i;
}
public int getAge(){
return age;
}
}
对象
对象是类的一个实例(不是女朋友哦),有属性(状态)和方法(行为).
对象的创建和使用
-
使用new +构造器创建一个新的对象;
-
使用“对象名.对象成员”的方式访问对象成员(包括属性和方法);
遇到new关键字JVM的详细操作:
在方法区要检查要创建的对象所属的类模板信息是否存在(类是否已经加载)
如果不存在, 必须由类加载器加载类模板, 加载到方法区中, 永久保存它.
如果存在, 则不加载, 保证类模板在方法区中只有一份.
依据类模板中的所有属性定义信息, 在GC区中开辟空间. 获取到对象的地址.
把此空间全部写0. 底层操作 : memset(内存地址, 0, 长度); 效果是所有属性拥有0
检查属性是否有显式赋值, 如果有, 则执行显式赋值.
执行构造方法, 进一步对属性进行赋值等初始化工作.
把对象地址返回给创建者.
class Animal {
public int legs;
public void eat(){
System.out.println(“Eating.”);
}
public viod move(){
System.out.println(“Move.”);
}
}
public class Zoo{
public static void main(String args[]){
Animal xb=new Animal();
xb.legs=4;
System.out.println(xb.legs);
xb.eat();
xb.move();
}
}
属性
分类
按照对象的声明位置可分为成员变量和局部变量
- 成员变量
声明在类中方法外,它范围大寿命长
- 局部变量
声明在方法中,它范围小,寿命短
其中**成员可以使用修饰符修饰,局部变量无法使用访问控制修饰符! **
语法格式
修饰符 返回值类型 方法名(参数列表){
方法体;
}
修饰符 : public private protected
返回值类型: return 语句返回值类型
举例
public class Person{
private int age;
public String name = "Liming";
}
方法
java程序中某个功能的封装, 一个独立的功能体. 也称为函数
语法格式
修饰符 返回值类型 方法名(参数列表){
方法体;
}
修饰符 : public private protected
返回值类型: return 语句返回值类型
- 举例
public class Person{
private int age;
public int getAge() { return age; } //声明方法getAge
public void setAge(int i) { //声明方法setAge
age = i; //将参数i的值赋给类的成员变量age
}
}
注意
-
没有具体返回值的情况,返回值类型用关键字void表示,那么该函数中的return语句如果在最后一行可以省略不写。
-
定义方法时,方法的结果应该返回给调用者,交由调用者处理。
-
方法中只能调用方法,不可以在方法内部定义方法。
-
方法的返回值只有一次机会接收, 就是在调用时
-
如果在方法中又调用了方法本身, 称为递归调用
-
方法永远无法修改另一个方法的局部变量.
-
不可以在方法内定义另一个方法
-
匿名对象可作为实参给方法调用
重载
- 概念:同一个类中,方法名相同,参数列表不同的方法之间构成方法的重载,调用时,根据方法参数列表的不同来区别。
- 说明:1.参数列表不同:参数的个数不同,参数的类型不同
2.与形参列表重参数名、返回值类型、权限修饰符都没关系
参数传递
-
形参:方法声明时的参数
-
实参:方法调用时实际传给形参的参数值(值传递)
值传递
- 如果参数是基本数据类型的变量,那么传递的就是此基本数据类型变量赋的值
- 如果参数是引用数据类型的变量,那么传递的就是此引用数据类型变量保存的地址值
注意:方法在调用时实参是通过值传递给形参数据, 本质上就是一个赋值操作. 值传递更安全
- 可变个数形参的方法:可变个数的形参必须作为方法形参的最后一个参数出现
public class Test{
public static void test(int a ,String... args){
}
public static void main(String[] args){
}
}
构造器
本质上是一个方法,但是有其特殊性.(凡是类,都有构造器)
- 方法名和类名一致, 唯一允许首字母大写的方法名
- 没有返回值声明, 甚至连void也不允许
- 不能被关键字 : static, final, synchronize, native, abstract等修饰
- 不能像普通方法一样随意调用, 只能调用一次. 某个对象的生命周期中只能调用一次.
- Java语言中,每个类都至少有一个构造器
- 默认构造器的修饰符与所属类的修饰符一致
- 一旦显式定义了构造器,则系统不再提供默认构造器
- 一个类可以创建多个重载的构造器
- 父类的构造器不可被子类继承
作用
- 创建类的对象
- 初始化创建对象的属性
格式
修饰符 类名 (参数列表) { 初始化语句;}
分类
按参数:(构造器之间是重载的)
- 隐式无参构造器(缺省)
- 显示定义一个或多个有参数构造器(显示定义了构造器后,编译器不再提供无参构造器)
代码块(初始化块)
定义
在类中,一对{}之间的语句
作用
用来初始化类、对象的基本的信息
非静态代码块
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 可以调用静态的变量或方法。
- 若有多个非静态的代码块,那么按照从上到下的顺序依次执行
- 每次创建对象的时候,都会执行一次, 且先于构造器执行
静态代码块
- 若初始化块有修饰符,其职能是static,成为静态代码块,当类被载入时,类属性的声明和静态代码块被先后顺序执行,且只被执行一次.(优先于构造器)
- 可以有输出语句。
- 可以对类的属性、类的声明进行初始化操作。
- 不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
- 若有多个静态的代码块,那么按照从上到下的顺序依次执行。
- 静态代码块的执行要先于非静态代码块。
- 静态代码块只执行一次
内部类
定义
将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类
类A中声明类B(包括类A的方法中),A为外部类,B为内部类
分类
成员内部类
-
静态成员内部类 (无需对象)
一个类若有static修饰,只有这一种情况,即静态内部类,虽说是静态类,但是不可被静态二字迷惑,其与静态属性,静态方法不同,只要是类,就必须实例化.
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
class Outer{
int a = 10;
static int b = 5;
public Outer(){
}
static class Inner{
int c = 3;
public Inner(){
}
public void test(){
//System.out.println(a); 内部类无法直接访问外部类的非静态成员,需要创建外部类对象才可
Outer outer = new Outer();
System.out.println(outer.a);//这样才可以
System.out.println(b);
}
}
}
public class InnerTest {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = new Outer.Inner();
inner.test();
}
}
- 非静态成员内部类 (需要对象)
class Circle {
double radius = 0;
public Circle() {
}
public Circle(double radius){
this.radius = radius;
}
class Draw{
double radius = 3;
public void drawShape(){
System.out.println("drawShape " + Circle.this.radius); //内部类访问外部类同名非静态属性
System.out.println("Outer's cnt " + Circle.cnt); // 内部类访问外部类静态属性
System.out.println(radius); //内部类访问本内部类类属性
}
}
}
public class InnerTest {
public static void main(String[] args) {
Circle circle = new Circle(5);
Circle.Draw draw = circle.new Draw();
draw.drawShape();
}
}
局部内部类(匿名内部类)
局部内部类是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
class People{
public People(){
}
}
class Man{
public Man() {
}
public People getWoman(){
class Woman extends People{ //局部内部类
int age = 0;
}
return new Woman();
}
}
注意: 局部内部类就像是方法里面的一个局部变量一样,是不能有 public、protected、private 以及 static 修饰符的。
匿名内部类:没有名字的内部类(涉及到接口和抽象类)
- 匿名内部类不能定义任何静态成员、方法。
- 匿名内部类中的方法不能是抽象的;
- 匿名内部类必须实现接口或抽象父类的所有抽象方法。
- 匿名内部类访问的外部类成员变量或成员方法必须用static修饰;
//定义接口
interface Product{
public double getPrice();
}
//定义抽象类,实现接口
abstract class Product2 implements Product{
}
public class InnerTest {
public void test(Product product){
System.out.println(product.getPrice());
}
public static void main(String[] args) {
InnerTest test = new InnerTest();
test.test(new Product() {
@Override
public double getPrice() {
return 888;
}
});
test.test(new Product2() {
@Override
public double getPrice() {
return 33;
}
});
}
}