@(笔记)[面向对象|MarkDown]
07.10
面向对象之关键字
new
要谈new关键字,就必须先说说构造方法,它们2个就是一对好基友.
构造方法
定义
- 无参构造方法:
访问修饰符 类名(){ }
- 带参构造方法
访问修饰符 类名(参数列表){ }
说明
- 构造方法可以被重载;
- 没有返回类型(void也算返回类型,只是没有返回值);
- 方法名和类名必须一样;
- 如果不写,系统会默认提供一个无参构造方法;
- 如果写了,系统就不会提供任何构造方法;
- 子类不能继承父类的构造方法;
- 接口没有构造方法;
作用
产生对象
new 一个对象的时候构造器所要做的事
1. 创建空间;
2. 划分属性;
3. 初始化值;
4. 执行构造方法内的语句;
实例化一个对象
用new关键字实例化一个对象时,所用做的事:
People p = new People();
1. 加载People,class文件进入内存;
2. 在栈内存为p变量申请一个空间(4个字节);
3. 在堆内存为People对象申请空间(大小为类中所有成员变量的大小);
4. 对类中的成员变量进行默认初始化;
5. (如果有)对类的成员变量进行显示初始化;
6. 有构造代码块,先执行构造代码块中的语句;
7. 执行构造方法中的语句;
8. 把堆内存的引用赋给p变量;
static
(类级别的,与对象无关)
可以修饰属性,方法,代码块和内部类;
static修饰属性(类变量)
- 那么这个属性就可以用
类名.属性名
来访问,也就是使这个属性称为本领的类变量,为本类对象所共享;
static修饰方法(静态方法)
- 会使这个方法称为整个类所公有的方法,可以用
类名.方法名
访问; - static修饰的方法,不能直接访问本类中的非静态成员,但本类的非静态方法可以访问本类的静态方法;
- 在静态方法中不能出现
this
关键字; - 父类中是静态方法,子类中不能覆盖为非静态方法;
- 在符合覆盖规则的前提下,在父子类中,父类中的静态方法可以被子类中的静态方法覆盖,但是没有多态;
- 在使用对象调用静态方法时,其实是在调用编译时类型的静态方法;
static修饰初始化代码块
- 此时初始化代码块叫做静态初始化代码块,这个代码块只在类加载时被执行一次;
- 可以用静态初始化代码块初始化一个类;
- 动态初始化代码块,些在类体的
{}
中,这个代码块在生成对象时运行;
例子
class StaticTest{
static int a = 3;
static int b ;
static void method(int x){
System.out.println("x = " + x);
System.out.println("a = " + a);
System.out.println("b = " + b);
}
static {
System.out.println("静态初始化代码块");
b = a * 4;
}
public static void main(String[] args){
method(5);
}
}
输出结果:
静态初始化代码块
x = 5
a = 3
b = 12
执行顺序
1. 首先加载StaticTest
类,在静态区开辟空间,给a
赋值为3
,b
赋值为0
;
2. 接着执行静态初始化块,先打印一条语句,然后把a*4
的值赋给b
;
3. 然后把main()
方法调入栈中,main()
调用method()
方法,把3
传给x
;
4. 然后打印;
注意:在一个static方法中引用任何实例变量都是非法的.
main()中的static
一般情况下,主方法是静态方法,所以可调用静态方法,主方法为静态方法是因为它是整个软件系统的入口,而进入入口时系统中没有任何对象,只能使用类调用。
说明
在有static定义的类的外面,static方法和变量能独立于任何对象而被使用.
例如想从类的外部调用一个static方法:
className.method();
或者调用一个static属性:
className.属性名;
这就是Jaba如何实现全局功能和全局变量的一个控制版本.
例子
class StaticDemo{
static int a = 42;
static int b = 99;
static void callMe(){
System.out.println("a = " + a);
}
}
class StaticByName{
public static void main(String[] args){
StaticDemo.callMe();
System.out.println("b = " + StaticDemo.b);
}
}
输出结果:
a = 42
b = 99
最后一点:static成员不能被其所在class创建的实例访问的.
简单来说
1. 如果不加static修饰的成员是对象成员,也就是归每个对象所有;
2. 加static修饰的成员是类成员,就是可以由一个对象直接调用,为所有对象公有.
从内存的角度来看static
类加载的过程中,类本身也是保存在文件中的(字节码文件保存着类的信息),
java通过I/O流把类文件读入JVM,这个过程称为类的加载.
JVM会通过类路径(classpath)来找字节码文件.
需要的时候才会进行类的加载,生成对象时是先加载后构造.
类变量,会在加载时自动初始化,初始化规则和实例变量相同.
注意:
类中的实例变量是在创建对象时被初始化的.
static修饰的属性,是在类加载时被创建并进行初始化,
类加载的过程只有一次,也就是类变量只会被创建一次.
静态非静态成员的调用
- 静态成员能直接调用静态成员;
- 非静态成员不能调用静态成员,能调用非静态成员;
原因:
从内存的角度,static修饰的成员是随着类的加载而创建的,
如果此时用静态成员调用非静态成员,则会报错,
因为在内存中还没有这个非静态成员;
非静态成员只有在实例化对象的时候才在内存中创建,所以非静态成员可以调用静态成员.
说白了就一句话:
先出生的不能娶还没有出生的;(指腹为婚不在讨论的范围之内)
后出生的长大了可以娶先出生的(现在很流行啊),也可以娶一起出生的;
final
最终的意思,不允许改变;
可以修饰变量,方法和类.
final修饰变量
- 一旦被final修饰的变量,就会变成常量,不能被重新赋值.
- 常量可以在初始化的时候直接赋值,也可以在构造方法里赋值,
- 只能二选一,不能为常量重新赋值;
- 常量没有默认值;
- 锁定栈,使栈中的数据不可以改变;
- 静态常量只能在初始化时直接赋值;
关于引用的问题
问题:使用final修饰的变量,是引用不能变还是引用的对象不能变?
final StringBuffer a = new StringBuffer("finalTest");
a = new StringBuffer("");//报编译器错误
a.append("finalTest");//这样可以
所以被final修饰的变量,是引用变量不能变,引用变量所指向的对象中的内容还是可以改变的.
final修饰方法
被final修饰的方法就不能被子类重写.
final修饰类
- 被final修饰的类将不能被继承.
- final类中的方法也都是final的.
注意:
final不能用来修饰构造方法.
public static final int MAX = 100;
常量属性定义为static,节约空间
final:因为用final修饰,所以是个常量
public:因为是常量,所以不能更改,public修饰给别人看也没事
static:共享,这样就不用new出来才能使用;
补充说明:
内部类要访问局部变量时,局部变量必须定义为final.
为什么局部内部类不能访问没有被final修饰的局部变量?
从内存中看,当方法里的局部变量所在方法结束时,该变量即在栈内存中消失;而内部类其实是一个类,只有内存中对它的所有引用都消失后,该内部类才”死亡”,即内部类的生命周期可能比局部变量长。如果局部内部类能访问一般的局部变量,则在多线程中,可能当方法结束后,局部内部类(是线程类时)还在使用局部变量。为了避免方法内的变量脱离方法而存在的现象发生,于是java规定局部内部类不能访问一般的局部变量。但能访问被final修饰的局部变量。因为常量放在堆内存中的数据段的常量池中
finally
是异常处理语句的一个部分,是异常的同意出口,表示总是执行.
就算是没有catch语句同时又抛出异常的情况下,
finally代码块仍然会被执行。
最后要说的是,finally代码块主要用来释放资源,比如:I/O缓冲区,数据库连接
finalize()
是Object类的一个方法,在垃圾收集器执行的时候,
会调用被回收对象的此方法,
可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等.
JVM不保证此方法总被执行.
abstract
- 抽象类不能实例化对象,但是有构造方法,抽象类中可以包含属性,抽象类中的构造方法是用来初始化成员属性的;
- 所有抽象对象必须被重写,除非子类也是抽象类;
- 可以存在没有抽象方法的抽象类;
- 有抽象方法的类必须定义为抽象类;
abstract type name_method();
- 只能修饰方法和类;
剩下的详细总结将在面向对象的特征中介绍.
instanceof
A instanceof B
A对象是否是B对象的实例
public boolean equals(Object obj){
if(obj instanceof Student){
if(student.name.equals(name))
return true;
}
return false;
}
this
- 对当前类的引用;
- 每个对象都有一个隐含的this变量,它可以访问类的所有信息;
- 构造方法的相互调用,必须放在构造方法内的第一个语句;
在重载的构造器中,为了重复利用代码
class Gril {
private int age;
private String name;
//构造方法
public Gril(int age ,String name){
this(name);
this.age = age;
//this.name = name;
}
public Gril(String name){
this.name = name;
}
public Gril(){
}
//睡觉的方法
public void sleep(Car car){
System.out.println("在车上睡觉");
}
public void sleep(Bed bed){
System.out.println("在床上睡觉");
}
public void sleep(){
System.out.println("在野外睡觉");
}
}
super
this和super详解
1. this
this.–>此时的this代表当前对象,可以操作当前类中的所有属性和方法;也可以操作当前类父类访问修饰符允许的方法和属性
- super代表当前对象的父类,只能操作当前类父类中访问修饰符允许的属性和方法;
- this不能看到的时候,super也看不到,this能看到的,super还是看不到;
- 只有在发生重写的时候,才用super调用当前对象的父类中同名的方法和属性;
- this()调用本类的其他构造方法;
- super()调用当前对象的父类的构造方法;
- 都只能放在构造方法的第一行;
- this()没有默认;
- super()为默认公共无参构造;
关于super更详细的介绍将在面向对象之继承中见到.