一.数组
1.一维数组:
a.定义格式:数据类型 [] 数组名 (推荐使用) 如:int[] a ; 数据类型 数组名 [] 如:int a[]
b.初始化:
- 动态初始化:只给出数组长度,系统默认初始值 如:int [] a=new int[10];
- 静态初始化:给出值,系统默认长度 如:int [] a={1,2,3};
- 注意事项: 静态初始化和动态初始化不同同时使用 如: int[] arr = new int[3] {1, 2, 3} //错误
c.初步了解java内存分配:
栈:存储局部变量(在方法定义或方法声明中定义的变量),栈中的数据使用完毕就消失;
堆:new出来的东西;每一个new出来的东西均有地址,每一个new出来的东西均有默认值;数据使用完毕后,就会变成垃
圾,在垃圾回收器空闲的时候被其回收。
方法区:存放方法及常量;
本地方法区(与系统文件相关):
程序计数器:存放字节码指令的地址,控制指令的执行顺序。
d.数组内存图:
int[] a=new int[3];
第一步:在栈中声明一个数组变量a,其空间是4个字节(变量名都为4个字节);
第二步:在堆中开辟一个长度为3的数组,并将数组元素赋予初始值0;
第三步:将堆中数组的地址(逻辑地址)存入变量a中;
2.二维数组:
(1)元素是一维数组的数组。
(2)格式:
- A: int[][] arr = new int[3][2]; //看作3个长度为2的数组
- B: int[][] arr = new int[3][];初始化:arr[0]=new int[2]; arr[1]=new int[3]; arr[2]=new int[1];
- C: int[][] arr = new int[][] {{1, 2, 3}, {4, 5}, {6}};
- 简化格式 int[][] arr = {{1, 2, 3}, {4, 5}, {6}};
(3)三种格式的内存图:
A:
B:
null表示将该内存区域清空,不指向任何区域。
C:
二:面向对象思想:程序等于=对象+消息;
洗衣服:
面向过程:把脏衣服放在桶里 --> 加洗衣粉 --> 到水,浸泡半小时 --> 搓上10分钟 --> 清洗 --> 拧干 --> 晾衣服
面向对象:把脏衣服放在桶里 --> 洗衣机(洗衣服) --> 晾衣服把专业的事情交给专业的人去做。
对象的初始化过程:
Student s=new Student();
代码:Student s = new Student();做了哪些事情?
- (1)加载Student.class到内存
- (2)在栈上开辟为s变量开辟内存空间
- (3)在堆上申请为对象申请内存空间
- (4)对对象的成变量进行默认初始化
- (5)对成员变量进行显示初始化
- (6)执行构造方法
- (7)将对象的地址赋值给s变量
一个对象的内存图:
class Tel {
String brand;
double price;
String color;
public void call(String name) {
System.out.println("我给" + name + "打了通电话.");
}
public void sendMessage(String name) {
System.out.println("我给" + name + "发了条短信.");
}
public void playGame(String name) {
System.out.println("我玩了局" + name + ".");
}
}
该代码加载执行顺序为:首先将TelDemo.class和Tel.class文件加载到方法区,其中包含其成员变量和成员方法;main方法入栈
执行Tel phone1=new Tel(); 此时便会执行上述的对象初始化过程。
注意:类的方法区里存有类的全部信息(成员方法与成员变量),而堆中new出来的对象仅含成员变量,无成员方法;
成员变量和局部变量的区别:
(1)在类中的位置不同
成员变量:成员位置
局部变量:方法内或者方法声明上
(2)在内存中的位置不同
成员变量:堆
局部变量:栈
(3)生命周期不同
成员变量:随着对象产生而开始,随着对象的消亡而结束
局部变量:随着方法的入栈而开始,随着方法的出栈而结束
(4)初始化值不同
成员变量:默认初始值
局部变量:不赋值不能使用
匿名对象
(1)没有名字的对象
new Student()
(2)应用场景
a:调用方法,仅仅只调用一次的时候。
new Student().study();
b:可以作为实际参数传递。
Static关键字:
静态的意思是:可以修饰成员变量和成员方法,表示该成员属于整个类所有;
静态的特点:
A: 随着类的加载而加载
B: 优先于对象而存在
C: 被类的所有对象共享
D: 通过类名直接调用,也可以通过对象名调用,推荐使用类名调用
静态的内存图:
静态的注意事项:
a. 在静态方法中没有this关键字
b.静态方法中只能访问静态的内容
静态变量和成员变量的区别
A:所属不同
静态变量:类
成员变量:对象
B:内存位置不同
静态变量:方法区的静态区
成员变量:堆
C:生命周期不同
静态变量:随着类的加载而开始,类的消失而结束
成员变量:随着对象的创建而开始,随着对象的消亡而结束
D:调用不同
静态变量:同过类名直接调用(推荐使用),通过对象调用(不推荐)。
成员变量:只能通过对象调用
(6)main方法是静态的
public: 因为main()是被JVM调用, 所以访问权限得够大
static: main()是程序的入口, 被调用的时候还没对象存在
void: 将返回值返回给JVM是没有意义的
main: 约定俗成的名字
String[] args: 早期用来接收键盘录入的数据
代码块:
(1)用{}括起来的代码。
(2)分类:
A: 局部代码块:
限定变量的生命周期,及早释放内存空间,提高利用率
{
int a=3;
System.out.println("a++");//该代码执行完后,变量a的内存将回收
}
B: 构造代码块:
将构造方法的最前面的相同内容抽取出来,放在构造代码块中,用于给对象进行初始化
每次创建对象都会执行 。
class CodeBlockDemo1 {
static {
System.out.println("这是静态代码块");
}
// 构造代码块
{
System.out.println("开始构建对象...");
}
public CodeBlockDemo1() {
//System.out.println("开始构建对象...");
}
public CodeBlockDemo1(int a) {
// System.out.println("开始构建对象...");
System.out.println("a=" + a);
}
// ...
public static void main(String[] args) {
/*// 局部代码块
{
int a = 10;
System.out.println("a=" + a);
}
System.out.println("a=" + a);*/
new CodeBlockDemo1();
new CodeBlockDemo1(10);
}
// 这是静态代码块
// 开始构建对象...
// 开始构建对象...
// a=10
}//因为静态代码块在类被初始化时就会执行,所以先执行静态代码块;接着是构造代码块,因为构造代码块里的内容是从构造方法里提取出来的,所以每次创建对象时就会执行构造代码块里的内容。
C: 静态代码块
给类进行初始化
随着类的加载而执行的,只执行一次
D: 同步代码块(后面讲)
(3)静态代码块,构造代码块,构造方法的顺序问题?
静态代码块 > 构造代码块 > 构造方法
类的加载顺序总结:
静态区域(静态成员+静态块)在类的加载时完成;非静态成团变量只有在new一个对象时才完成初始化。
顺序如下:
- 父类静态区域
- 子类静态区域
- 父类非静态成员
- 父类构造方法
- 子类非静态成团
- 子类构造方法
继承:
1. 继承
(1)把多个类中相同的成员给提取出来定义到一个独立的类中。然后让这多个类和该单独的类产生一个关系,使多个类中具备这个单独的类中定义的成员。
这个关系叫继承。
(2)Java中如何表示继承呢?格式是什么呢?
A:用关键字extends表示
B:格式:class 子类名 extends 父类名 {}
(3)继承的好处:
A:提高了代码的复用性
B:提高了代码的维护性
C:让类与类产生了一个关系,是多态的前提
(4)继承的弊端:
A:让类的耦合性增强。这样某个类的改变,就会影响其他和该类相关的类。
设计原则:低耦合,高内聚。
耦合:类与类的关系
内聚:自己完成某件事情的能力(责任)
B:打破了封装性
(5)Java中继承的特点
A: Java只支持单继承,不支持多继承
B: 但是支持多层继承 界门纲目科属种
(6)继承的注意事项:
A:子类不能继承父类的私有成员(私有成员是被子类隐式继承的,其实私有成员被继承了,但是在子类中不能访问。反射)
B:子类不能继承父类的构造方法,但是可以通过super去访问
C:不要为了部分功能而去继承。
(7)什么时候使用继承呢?
继承的原则:
A类和B类如果是: is a
is a的关系:
Person:
Student
Teacher
(8)Java继承中的成员关系
A:成员变量
a:子类的成员变量名称和父类中的成员变量名称不一样。
b:子类的成员变量名称和父类中的成员变量名称一样,这个怎么访问呢?
子类的方法访问变量的查找顺序:
首先找子类的局部变量
再找子类的成员变量
再找父类的成员变量
B:构造方法
a:子类的构造方法默认会去访问父类的无参构造方法
目的:将在父类中定义的成员变量初始化。
b:父类中如果没有无参构造方法,怎么办?
子类通过super去明确调用带参构造
子类通过this调用本身的其他构造,但是一定会有一个去访问了父类的构造
让父类提供无参构造
this(...), super(...)只能在构造方法的第一条语句。C:成员方法
a:子类的成员方法和父类中的成员方法签名不一样。
b:子类的成员方法和父类中的成员方法签名一样,这个怎么访问呢?
通过子类对象访问一个方法的查找顺序:
查找子类的成员方法
再查找父类的成员方法(没有就报错,不考虑父亲的父亲)
![]()
(9)两个面试题:
A:Override和Overload的区别? Overload是否可以改变返回值类型?
override: 子类重写父类的同名方法。要求子类的返回值类型要被父类兼容,方法名一样,参数列表一样。子类的访问权限不能比父类的小。
overload:在同一个类中,方法名一样,但是参数列表不一样。与返回值类型无关
如果在子类中定义了一个和父类同名的方法,但是参数列表不一样就会构成重载。
如果在子类中定义了一个和父类同名的方法,但是参数列表一样,但是返回值类型不兼容,会报错。
B:this和super的区别和各自的作用?
this
this.成员变量 super.成员变量
this(...) super(...)
this.成员方法() super.成员方法()
(10)数据初始化的面试题(了解)
A:子类对象的初始化过程
B:子父类的构造执行过程
加载父类
加载子类
对父类进行初始化
对子类进行初始化
C:分层初始化2 :final关键字
(1)是最终的意思,可以修饰类,方法,变量。
(2)特点:
A:修饰类,表示这个类不能被继承(绝育手术)
B:修饰变量,表示该变量使常量,它的值不能被修改
基本数据类型:里面的值不能被修改
引用数据类型:它的地址值不能被修改,指向同一个对象,但是对象的内容可以修改
注意事项:
被final的变量必须进行显示赋值
只能被赋值一次,即使值相同。
C:修饰方法,表示该方法不能被子类重写
例题分析:
分析:首先JVM执行main方法,便将Test2类加载到方法区中进行初始化,要执行new Z()时,便准备初始化Z类,但由于Z类继承X类,所以 优先初始化X类,在X类中有static区域,所以先执行静态区域;然后回到z类,初始化的同时执行静态区域的内容;接着准备执行Y b=new Y()时就会加载Y类,至此所有类均初始化完毕。
output:
this is Static X
this is Static Z
this is constuction Y
this is y
this is constuction X
this is x
this is constuction Y
this is y
this is z