目录
说一下构造代码块的问题
如果所有对象都需要自动执行的一段代码,我们就可以放到构造函数里面,也就是说,把这个代码块放到构造函数里面。但是,有一个问题,我们每次new一个对象,都会在推上面开一个空间来放这些函数代码,有点浪费空间。
那如果我们放到构造代码块里面呢。他放在方法区,公共区域,也就是说,new的时候,每一个对象都会指向这个区域,而不会单独开一个空间,浪费内存。
这个的执行方式:
{...}
另外还有一个静态代码块:
static{
。。。。。。.class文件加载到内存就执行了。他不需要对象,静态就不需要对象
}
然后还有一个自动执行的函数代码:
构造函数。。。
那么它们到底谁先调用?
静态构造代码块-》构造代码块-》构造函数
下面直接上代码具体说一下子父类构造函数,构造代码块,静态构造代码块的执行顺序
Demo4.java
package pxx;
public class Demo4 extends Demo4Father{
public static void main(String[] args) {
Demo4 demo4 = new Demo4();
}
public Demo4(){
System.out.println("子类构造函数调用了");
}
{
System.out.println("子类构造代码块调用了");
}
static {
System.out.println("子类静态代码块调用了");
}
}
class Demo4Father {
public Demo4Father() {
System.out.println("调用了父类的无参构造");
}
{
System.out.println("父类构造代码块调用");
}
static {
System.out.println("父类静态代码块调用了");
}
}
运行结果:
首先必须知道两个大的前提:
1.父类是优先于子类进行初始化操作
2.静态代码块最先执行,类一加载到内存就会执行
那么上面的代码一分析就会知道:子父类的静态代码块先调用,父类又比子类优先,所以,先打印父类的静态代码块,然后打印子类的静态代码块,然后又调用父类的构造代码块,无参,调用子类的构造代码块,构造函数。
关于构造函数与this的深刻讲解
构造函数可以有多个,然后构造函数之间是可以彼此调用的,但是这个调用要通过this实现,必须是在第一个语句。然后根据参数的不同,调用不同的构造函数。可以解决构造函数对象属性与形参同名的问题,但是没有this也不会报错,有默认参数。当然,this只能在非静态函数中使用(this的存在必须有对象)
静态函数
这个也叫类方法,首先静态函数是不能直接,注意是直接,不能直接访问非静态成员与函数,因为它是先于对象存在的,由类直接参与调用。但是如果静态函数中,实例化了一个对象,那他就可以访问非静态成员与函数了啊。
问题:如果一个函数没有直接访问非静态成员与方法,那么这个函数,就可以设置成静态函数。因为这样,我们无需对象也可以调用,常常用于工具类,比如Arrays中的toString sort方法:
内部数据一般都是按照升序排列
举个例子:下面是我们自己写的一个工具类,里面有一个排序方法
上面的方法,然后其他类就可以去调用,通过类名就可以进行调用
说一下主函数的意思:
public static void main(String[] args) {
//说一下这个设计的好处
}
jvm就是一个虚拟机,固有思维,固定限制
main:jvm虚拟机来调用的,从任何情况都可以访问,程序的主入口
statics:jvm不知道怎么创建对象,因为要传参数,所以jvm就像一个无头苍蝇
arguments:这个就是在执行字节文件的时候,我们可以传入参数进去,也有可能是说,程序启动需要一些参数。
上面就是我们程序在运行的时候,就需要传入启动参数
上面就是cmd中启动程序,传入了一些参数
java的继承模式
java是单继承,也就是我们一次只能继承一个父类。我们可以通过继承间接往上面继承,继承之后默认调用父类的无参构造函数。
不用继承,如果一个对象内部要依赖于一个对象的东西,公共的一个东西,那么实现起来就比较麻烦:
一个对象内部的函数,可能需要去调用另外一个对象的函数,那么我们可能在一个对象内部传入一个对象,然后去调用内部的方法
首先,子类一定会去调父类的无参构造函数。当有一个有参的构造函数时,如果没有无参存在,父类将会出现错误,前提是没有调用有参。子类想写自己的构造函数,就必须隐式调用父类无参构造函数。
super代表父类空间的引用,包括引用成员属性与方法,super.属性名 super.方法名()。当调用父类构造方法时,必须放在第一条语句,所以,无法与this同时存在一条构造方法中(前提是在调用构造函数的时候)
说一下,父类重写的方法:注意重写与重载不一样
重载;根据参数个数的不同,类型的不同,来进行同名函数重载,与返回值无关
方法重写前提:存在继承关系,子类的方法与覆盖父类的方法,这也是一种多态的体现。
我们如何才能实现重写:
下面说一下instanceof: 对象 instanceof 类别 失败直接返回错误,成功返回true
前提:判断的对象必须与类有继承或者实现的关系
继承一个对象,然后在new一个对象,然后用new的对象去进行判别
如果是一个接口,然后去实现这个接口,我们在用实现接口这个类的对象去进行判别
final关键字
最终的,它也属于一种修饰符
1.修饰基本类型成员变量时,该变量不能重新赋值(所以第一次注意进行初始化)
2.fianl关键字修饰一个引用类型变量时,该变量不能重新指向新的对象。
3. final关键字修饰一个函数的时候,该函数不能被重写。
4. final关键字修饰一个类的时候,该类不能被继承。
5. final关键字定义的变量不能被修改。
6.一般我们在类里面定义一个常量:public static final .....这就是一个静态成员
7.final定义的函数不能被重写,但是可以被重载
下面看一下,一些不能被继承的类:
可见一些常见的数据类型相关的类都是final类型的,不能被继承,那就更不可能被重写了
下面讲一下abstract类
讲一下需求:在你定义的的类,需要多个类去继承的时候,他们有一个共同的方法,而这个方法的具体内容不一定,我们就需要设置成抽象方法
- 抽象类里面可以有抽象方法与非抽象方法
- 抽象方法就是需要子类去实现的方法,抽象类不可以设置成final类,因为它就是要被继承的,他不能实例化对象。因为对象要调用方法,但是抽象类里面可能就没有方法的实体
- 抽象类可以有构造函数,子类就可以去调用
- 有抽象方法就必须定义成抽象
- 抽象方法不能与private共用,很明白,Privated的方法与属性不能被继承
简单来说一下权限修饰符的问题
protected与default定义的方法,都不能在跨包之后直接进行访问。default挎包之后不能被继承,不能被访问
protected挎包之后可以被继承下来,但是不能在外部直接进行访问
抽象方法不能与final共用,很明白,方法不能被重写,更不要说你要去修改它,完善它了。
抽象方法不能与static共用,因为先于对象存在,所以他可能会去调用这个方法,但是如果这个方法不存在,那么就可以造成错误。
下面来说一下值传递
函数传递的就是变量的值
上面这种情况就是把值修改成功了。分析一下changeData里面传入了一个接收了一个Data对象,但是我们分析一下这个过程,这个Data d1与这个Data d它们肯定不是同一个内存地址的变量,但是他们却是指向了堆里面相同的内存空间,所以他们可以进行数据的修改。
接口
接口,就是拓展功能用的。接口其实就是一种抽象特殊类
interface 接口名(所有首字母大写,按照类名处理)
{
1.接口中的成员变量全是常量默认修饰符public static final ,不可改,所以这个都是内部初始化好的
2.接口中的方法全是抽象方法,让类去实现的(默认是public abstract)
3.一个非抽象类去实现接口的时候,必须把接口中的所有抽象方法全部实现
4.接口不能创建对象
5.接口没有构造函数
6.jdk1.8之后,接口内部可以有默认的default方法
}
接口完全就是什么都定义好了给实现它的函数用,所以不需要构造函数传值。
接口实现方法:
class 类名 implements 接口名
{
....
}
接口的作用:
1. 程序的解耦。 (低耦合)
2. 定义约束规范。
3. 拓展功能。
一般我们定义接口的时候,里面默认的方法是:
public abstract ...但是一般我们会把这两个关键字给省略掉
回过头来说一个小问题:
java是单继承,多实现,也就是说,我们去实现接口的时候,一次性我们可以实现很多接口,接口之间也可以继承很多接口,具体的方式如下:
多态
一种事务的多种形态,比如函数的重载,方法的重写
用父类变量指向子类对象:(基于父类来调用子类)
1. 成员变量静态与非静态都是访问的父类的
2.访问静态方法,调用的也是父类
3.访问非静态方法,调用的是子类的方法
4.不能访问子类特有的成员
上个代码Demo3.java
public class Demo3 {
public static void main(String[] args) {
//我们这里直接用多态来处理
Father father = new Son();
System.out.println(father.name);//这个调用是父类的成员属性,子类并没有,可以打印
//打印子类特定的成员
System.out.println(father.age);//子类特有成员访问不了
}
}
class Father {
String name = "我是父亲";
public void say() {
System.out.println("我是孩子付清");
}
public void eat() {
System.out.println("我是父亲,我可以吃饭");
}
}
class Son extends Father {
int age = 23;
public void eat() {
System.out.println("我是儿子,我也可以吃饭");
}
}
这里很明显就会给我们报一个错误:
那如何解决访问子类特有的成员呢:
数据类型转换,把相应的数据类型转换成相应的数据成员,参考代码如下:
上面可能就是需要我们把数据类型进行转换一下。