# JAVA SE
前言:本文是我的自学Java笔记,仅记录回顾所用,还未完善勿喷,图片未添加。文章是2020年写的,忘记发了,如有不对的地方请各位师傅指出,感谢!!!(尽快完善尽快完善)
事事难上难,举足常虞失坠。件件想一想,浑身都是过差。——清·金缨
第一章-java的简介
1、java是什么?
一种编程语言
高级编程语言:c/c++,java,php,javaScript,python…
因为计算机只能认识二进数,不能识别高级语言,所以所有的高级语言都需要转变为机器语言
- 高级编程语言分为二种:
-
编译型语言(c/c++):
- 需要先将源代码进行编译,转换为特定的可执行文件(平台能直接执行的二进制文件)
- 优点:编译一次,永久执行,当你发布可执行文件给客户时不需要提供源代码, 只需要提供一个可执行的二进制文件即可,体现了安全性、执行速度快
- 缺点:不能跨平台
-
解释型语言(javaScript,python):
- 需要一个解释器,在源代码执行的时候被解释器翻译为一个与平台无关的中间代码,之后再翻译成各平台的机器语言
- 特点:夸平台
- 缺点:运行时需要源代码,运行速度慢
-
2、java的发展历程
开始研究 | 1990 |
---|---|
Oak | 1991.6 |
HotJava | 1995.5 |
Java1.0 | 1995.5.23 |
Java1.1 | 1997.2.18 |
Java 1.2 | 1998.12.4 |
Java1.3 | 2000.5.8 |
Java1.4 | 2002.2.13 |
Java5.0 | 2004.9 |
Java6.0 | 2006.4 |
Oracle74亿美元收购sun | 2009.4.20 |
Java7 | 2011.7.28 |
Java8 | 2014.3.19 |
Java9 | 2017.9.21 |
… | … |
3、java的特征
- java的特征
- 半编译半解释
- java会将代码编译成一个.class文件(不完全编译),再将.class文件解释称各平台能够识别的机器语言
- 跨平台
- 速度快
- 安全
- 健壮
- 分布式:垂直分布式、水平分布式
- 多线程
- [面试题]jvm是什么?jvm的运行原理?jvm的生命周期
- jvm:java虚拟机(相当于一个翻译官)
- 运行原理:java编译器先将代码编译成.class,java虚拟机再将.class文件解释成各个平台能够识别的机器语言,每个平台都有自己的jvm因为有不同系统版本的jdk。
- 生命周期:当遇到main时候jvm开始运行,main方法运行完成的时候jvm结束;如果说有10个main同时执行,10java虚拟机在运行,他们互不影响。
4、java语言的版本
javaSE(java核心技术)、javaEE(java企业级开发技术,javaWEB)、javaME(小型版本)
5、安装JDK
-
无论使用什么样的编程语言开发,都要安装SDK,在java中称为JDK。JDK:JAVA开发工具包。JRE:JAVA运行环境
-
[面试题] JRE和JVM的关系?
答:JRE=JVM+基本的数据包+JAVA依赖包
-
JDK目录结构:bin:存放可执行文件 java.exe javac.exe,lib:存放一些二进制文件和所依赖的包
6、关键字,保留字,标识符
关键字:java中特殊的英文单词,内部编译器自动识别
保留字:暂定为java使用,还没有真正成为关键字,以后用不用还不确定
标识符:包、类、方法、参数和变量的名称总称为标识符
-
命名规则:
规则:
必须以字母、下划线(_)或美元符号($)开头;
余下的字符可以是下划线、美元符号或任何的字母或数字,长度不限;
标识符中不能有空格;
不能使用Java中的关键字或者保留字做为标识符; -
规范:
1、包:域名.公司名.项目名.种族 com.nesoft.java150219.test
2、类名:驼峰命名法 /_/_/\ 首字母一定要大写Student , HelloWorld ,Hello_world
3、方法名:驼峰命名法 /_/_/\ 首字母一般要小写 getName(),get(), set_sex()
4、参数和变量名:驼峰命名法 /_/_/\ 首字母一般要小写 int maxAge
5、常量名全部大写
7、String[] args java虚拟机默认传入的字符数组参数
第二章-数据类型
1、基本数据类型
数值型:
byte, short, int, long 一个字节8位 1G=1024m 1m=1024k 1k=1024b
byte 1字节8位 -2^7-2^7-1 ,即-127到128
short 2字节16 -2^15-2^15-1
int 4字节32位 -2^31-2^31-1 java中默认的整型
long 8字节64位 -2^63-2^63-1
long b4=12312312; //发生了隐式转换 12312312是int类型,自动转换long
long b5=12312312L; //一般声明Long类型数据时,在数据的后面加上L
Java中不同进制整型的表示形式
十进制 第一位不是0 例:10等
十六进制A:10 F:15 例:0xF 运算5*16^0+4*16^1=690x45
八进制 例:0125 运算:5*8^0+2*8^1+1*8^2 第一位是0
二进制 必须以ob开头 例:0b10101001
浮点型: double,float
double: 8字节 64位 -2^63-2^63-1 java中默认的浮点型
float: 4字节 32位 -2^31-2^31-1 float和long一样需要在变量值后加首字母
字符型:char
char 是字符时只能表示单个字符
char c2=49; //是整数时,是一个16位无符号整数 ,jvm会找到acsii表找到整数对应acsii值
转义字符: \ ,\n代表的是回车(换行)
System.out.println("你好,\"中国\"");
布尔型: boolean -->false=0 true=1 一般用于判断比较
2、变量
变量 :临时存放数据的场所
局部变量:在方法中或则代码块中声明的变量,一定是初始化之后变量才能使用
数据类型的相互转换
byte:1个字节 8位 -128~127
short :2个字节 16位 (-2^15~2^15-1)
int :4个字节 32位 (-2^31~2^31-1)
long:8个字节 64位 (-2^63~2^63-1)
浮点型:
float:4个字节 32 位
double :8个字节 64位
注:默认的是double类型,如3.14是double类型的,加后缀F(3.14F)则为float类型的。
char类型:
char:2个字节。
Boolean 类型:
boolean: (true or false)(并未指明是多少字节 1字节 1位 4字节)
1.隐式转换:就是把小精度的数值直接赋值给大精度数据类型,会发生隐式转换
例: short a1=10; int a2=a1;
2.显示转换:就是需要使用强制转换,当大精度的类型的数值要变小精度的类型数值时需要实现强制转换;
但可能会导致精度缺失,发生后果自负 例:int a=10;short b=(short)a;
3.byte、short、char之间不会相互转换,他们三者在计算时首先会转换为int类型
4.int接收的是一个字符,jvm会去找acsii表,char接收的是一个整型是,jvm会去找acsii表
3、赋值运算符
赋值运算符: + - * / %(求余)
1.赋值的时候从右往左计算,例将20赋给a int a=20;
2.a=a+10,可以写成a+=10; 加减乘除同理
4、算术运算符
1.++a先自增1,后运算
2.a++先运算后,后自增1
5、比较运算符
比较运算符>、<、>=、 <=、= =、!=、instanceof
1.比较运算符,返回boolean, if(){}的条件返回的也是boolean
boolean temp=1>2;
boolean t1=1!=2;
2.==用于数值类型比较 比较就是两个数值是否相同
boolean t2=1==2;
3.//instanceof 比较是否是同一个对象 用于引用类型数据
Date d=new Date();
Date d1=new Date();
boolean t3=d instanceof Date;
if(d instanceof Date) {
System.out.println("d是日期类型,可以转为字符串类");
}
6、逻辑运算符
&&逻辑与,||逻辑或(),逻辑非 !
1.&&逻辑与 表达式两边都为true才为true 表达式一&&表达式二
2.逻辑或 || 达式一边都为true就为true 表达式一||表达式二
3.逻辑非 对结果取反
if(!false) {
System.out.println("true");
}
7、按位运算符
按位运算符byte short char int long有效
按位运算符: & | ^ ~ >> << >>>
1. & 按位与 & 只有参加运算的两位都为1,&运算的结果才为1,否则为0
int i=5&2;
/* 0101 ---5
0010 ---2
0000 ---0*/
2. | 按位或 | 只有参加运算的两位都为0,|运算的结果才为0,否则为1
int j=29|5;
/*011101 --29
000101 --5
011101 --29*/
3. ^ 异或 只有参加运算的两位不同,^运算的结果才为1,否则为0
int h=29^5;
/*0001 1101 --29
0000 0101 --5
0001 1000--24*/
4. << 左移 << n<<m n*2^m 符号位:0代表正数 1代表负数
int k=5<<2;
/*0000 0101
0001 0100*/
5. >> 右移 >>
int g=5>>2;
/*0000 0101
0000 0001*/
6. >>> >>>:无符号右移。无论是正数还是负数,高位通通补0
7.左移的正负数,右移是正数,都可以套用公式 n>>m n/2^m
8.注意:负数的左移右移,将原码转为补码再移动,最后将得到的结果转为原码。
反码时原码取反, 补码是反码+1;
int num=-9<<2;
/*1000 1001 --原码
*1111 0110 --反码
*1111 0111 --补码
*
*1111 011100 --左移结果
*1111 011011 补码反反码
*1000 100100 //36 原码
*/
9.正数右移左边空余部分补0 负数右移左边空余部分补1
int num2=-9>>2;
/*1000 1001 --原码
*1111 0110 --反码
*1111 0111 --补码
*
*1111 1101 --右移结果
*1111 1100 补码转反码
*1000 0011 //-3 原码
*/
8、按位运算和逻辑运算的区别
1.表达式一&&表达式二 ,表达式一&表达式二
2.按位与& 逻辑与&&的区别:
&&具有短路功能,若果表达式一为false,不执行表达式二
&不具有短路功能 表达式一和表达式二无论如何都执行
3.表达式一||表达式二 ,表达式一|表达式二
4.按位或| 逻辑或||的区别:
||具有短路功能,若果表达式一为true,不执行表达式二
|不具有短路功能 表达式一和表达式二无论如何都执行
9、三元运算符
三元表达式:表达式1?表达式2:表达式3;
表达式1的结果为true时,就为第二个表达式,如果为false时,就为第三个表达式
技巧:从右往左计算
例如:boolean t1=false?true:false?false:false?true:false?true:false;结果为false
10、String类
String类: 引用类型(对象类型)和基本数据类型的区别
只要是变量的声明都放在栈区
基本数据类型数据存在栈区
引用类型数据类型存在堆区
new 内存空间分配符(在堆中)
1.声明变量初始化的时候就已经是在内存中创建了一个对象
2.==用于引用数据类型比较的时候,比较的时两个对象的地址
3.但内存中有对象了,就不会重新创建,例内存中已经有zhangsan了,如果再想创建String s4=new String("zhangsan"); //这样声明在内存中创了多少个对象 1个
4.若没有,String s4=new String("lisi"); //这样声明在内存中创了多少个对象 2个
5.System.out.println("y"+y); //任何数据类型和字符串拼接都会变成字符串
第三章-流程控制语句
1、if语句
if语句 :表达式为true那么执行if语句体;if(表达式){}
(1).单分支 if(表达式){}
(2).多分支
if(表达式){
}else if(){
}else{}
2、Switch语句
(1).switch (表达式){
case 取值1:
语句块1
…
case 取值n:
语句块n
default:
语句块n+1
}
(2).case的取值一定要和switch中的表达式的数据类型一致,case值必须是常量,不能跟变量。
(3).break:跳出switch语句
(4).switch语句的结束:
遇到break语句或者如果满足条件执行语句块,但是没有遇到break语句会继续往下执行直到遇到下一个break语句为止,如果没有break语句一直执行到switch语句的最后
3、for循环
(1).for(初始化表达式;循环条件表达式;循环后的操作表达式){
执行语句块
}
(2).死循环产生的条件:没有循环终止条件
(3).注意:死循环之后的代码都不能通过编译
死循环有:
for(;;){死循环1};
for(int i=0;;){死循环2};
for(int i=-1;i<=0;){死循环3};
for(int i=0;;i++){死循环4}
4、while和do…while
where(表达式){ 表达式做条件判断--boolean }
do{}while() 无论如何都会执行一次语句块
(1).while的死循环
while(true) {死循环1};while(i<100) {死循环2};
5、变量的作用域
(1).变量的作用域:变量要初始化之后才能使用;
在同一个作用域范围内,变量不能重新被定义;
(2).若变量在main方法声明,则在if或者其它语句中,不可重复声明;
若变量在if或者其它语句中声明,则只能在其语句中可使用,离开此语句不能使用;
6、控制台输入和随机数
(1).控制台输入:Scanner sc=new Scanner(System.in);//需要scanner包
sc.next();//读取一个字符串,以空格结束
sc.nextInt();//读取整数
sc.Double();//浮点型
sc.nextLine();// 读取控制台输入的一整行字符串数据
(2).随机数:Randow r=new Random();
r.nextInt(10)//表示随机获取0-9的数
r.nextInt(10)+1//表示1-10的数
7、循环嵌套和循环中断
(1)练习循环嵌套
// (1)循环嵌套:九九乘法表
for(int i=1;i<=9;i++) {
//行数
for(int j=1;j<=i;j++) {
//列数
System.out.print(j+"x"+i+"="+j*i+" ");
}
System.out.println();
}
(2)循环中断(break,continue)
① break
for(int i=1;i<=9;i++) {
//行数
if(i==5){
break;}//跳出整个循环
for(int j=1;j<=i;j++) {
//列数
System.out.print(j+"x"+i+"="+j*i+" ");
}
System.out.println();
}
②continue
for(int i=1;i<=9;i++) {
//行数
if(i==5){
continue;}//跳出整个循环
for(int j=1;j<=i;j++) {
//列数
System.out.print(j+"x"+i+"="+j*i+" ");
}
System.out.println();
}
③outer
outer:for(int i=1;i<=9;i++) {
//行数
inner:for(int j=1;j<=i;j++) {
//列数
if(i==5){
break outer;
}
System.out.print(j+"x"+i+"="+j*i+" ");
}
System.out.println();
}
二、数组(第四章)
1、数组:int[] arr1= {元素1,元素2…} 就一个容器
(1).特点:声明什么类型的数组就只能存放什么数据类型的数据;
数组是定长(数组长度不可变);
(2).当声明的数组没有给定值,会有默认的值
String(引用数据类型)-->null char-->' ' int-->0 double-->0.0
(3).int[] arr3=new int[5]; -->初始化时必须指定数组的长度
(4).数组的声明和创建,
①int[] arr={1,2};//创建并且初始化
②int arr[]={1,2};
③int[] arr=new int[5];//创建数组且长度为5;默认值为0;
④int[] arr=new in[]{1,2,3}
(5).声明一个int类型的数组 那么只能存放int类型数据
int[] arr1= {'a',2,3,4,5,5,5,123}; //发生char->int
(6).若给数组单独赋值,则不能超过数组函数长度,超过则出现数组越界异常
(7).通过Arrays类中的toString方法打印输出数组
System.out.println(Arrays.toString(arr));
2、数组内存分析
数组中的数据存放在堆内存,其引用在栈内存
int[] arr2= {}; //这样声明数组,数组没有长度,没有在对内存中创建数组对象
3、数组的访问
使用for循环访问数组 数组索引的最大值是数组长度-1(arr.length-1)
4、加强for循环 foreach 一般用于数组对象或者集合的遍历
String[] student={"a","b","c"};
for(String s:student) {
System.out.println(s);
}
5、二维数组
(1).创建方式①int a[行][列];int[][] b;int[] c [];
(2).快速访问
for(int row=0;row<f.length;row++) {
for(int colum=0;colum<f[row].length;colum++) {
System.out.print(f[row][colum]);
}
System.out.println();
}
第四章-数组
1、数组的操作
-
*什么是时间复杂度?
平方阶 (O(n2)) 排序 各类简单排序:直接插入、直接选择和冒泡排序。
线性对数阶 (O(nlog2n)) 排序 快速排序、堆排序和归并排序;
O(n1+§)) 排序,§ 是介于 0 和 1 之间的常数。 希尔排序
线性阶 (O(n)) 排序 基数排序,此外还有桶、箱排序。 -
关于稳定性
稳定的排序算法:冒泡排序、插入排序、归并排序和基数排序。
不是稳定的排序算法:选择排序、快速排序、希尔排序、堆排序。 -
名词解释:
n:数据规模
k:"桶"的个数
In-place:占用常数内存,不占用额外内存
Out-place:占用额外内存稳定性:排序后 2 个相等键值的顺序和排序之前它们的顺序相同
图片出处:https://www.runoob.com/w3cnote/sort-algorithm-summary.html
(1). 数组拷贝
System.arraycopy(src, srcPos, dest, destPos, length);
src源数组,srcPos开始复 制索引,dest目标数组,destPos开始粘贴索引,长度
System类中的数组拷贝方法对数组进行更新
(2). 数组的排序
2、其他算法
(1). 冒泡排序
//arr.length-1和arr.length-j-1的区别,
//arr.length-1就是每一个都要排序,无论是排过序的还要重新对比
//arr.length-j-1,不用重新排已经排好序的数据,提高了排序的效率
- 练习:
(2). 选择排序
在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;
第二次遍历n-2个数,找到最小的数值与第二个元素交换;
。。。
第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。

(3). 插入排序
基本思想: 在要排序的一组数中,假定前n-1个数已经排好序,现在将第n个数插到前面的有序数列中,使得这n个数也是排好顺序的。
如此反复循环,直到全部排好顺序。
(4). 快速排序
基本思想:(分治)
先从数列中取出一个数作为key值;
将比这个数小的数全部放在它的左边,大于或等于它的数全部放在它的右边;
对左右两个小数列重复第二步,直至各区间只有1个数。

(5). 归并排序
基本思想:
归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。
首先考虑下如何将2个有序数列合并。这个非常简单,只要从比较2个数列的第一个数,谁小就先取谁,取了后就在对应数列中删除这个数。然后再进行比较,如果有数列为空,那直接将另一个数列的数据依次取出即可。 先递归的分解数列,再合并数列
过程:
第五章-方法的定义和调用
1、方法的定义和调用
方法的声明:
[访问控制符] [修饰符] 返回值类型 方法名(参数类型 形式参数,参数类型 形式参数,…){
方法体
}
一个方法的结束的标志: 遇到return语句或者方法的结束 一个有返回值的方法只会执行一次return语句
成员变量(属性): [访问修饰符]数据类型 + 名(int age);
无参无返回值: void代表该方法没有返回值
public void getName() {
System.out.println("getName()");
}
有参无返回值: int age 是形式参数 --为了告诉开发者需要传入什么类型的参数
public void setName(int age) {
System.out.println("setName()");
}
无参有返回值: return 有返回值的方法必须有return语句 返回一个和声明方法时定义的返回值类型相同数据类型值
public int getAge() {
//业务逻辑处理后的一个结果返回给调用此方法的方法
int age=10;
return age;
}
注意:方法里面也可以调用其他的方法
public String getAge1() {
String studentName=null;
int age=getAge();
System.out.println(age);
if(age>5) {
studentName="wangwu";
}
return studentName;
//return 123; 必须和声明的数据类型一致
}
有参有返回值:
public boolean setAge(int sex) {
boolean s =true;
System.out.println("我的返回值是boolean");
return true;
}
注意:
1)调用有参的方法时,一定要给方法传入实参 --具体的参数 方法需要多少个参数,调用时就需要传多少个参数
2)有返回值的方法被调用后,获得的结果可以用对应的数据类型变量来接收 ,拿到结果后可以对结果进行进一步操作
2、方法的重载
方法的重载:
前提:在同一个类中
一同一不同:方法名相同参数列表不同(参数个数不同或者参数的类型不同);返回值可同可不同;
3、引用传递和值传递
引用传递:传递的是地址
值传递:传递的是值
内存图:
第六章-面向对象基础
1、类的对象
面向对象与面向过程的区别:
面向过程:就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了
面向对象:是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为
类的定义、属性、方法
类的定义:把相似的对象划归成一个类。
成员变量(属性):对象共同的特征的描述
成员变量和局部变量的对比
成员变量(属性):
1)声明在类中,是对象的成员;
2)存放于堆区,在对象被创建的时候就已经初始化有了默认值
作用域:1)声明过后,成员方法都可以使用
局部变量:1)声明在方法或者语句块中;2)存在在栈区
成员方法: 1)只有实例化后才可以使用(就是创建对象 new xxx)
注意:
1)成员属性和成员方法只有在实例化之后才能调用
2)在创建对象(实例化)时,就已经将所有的成员变量初始化,赋予了初始值
创建对象:
1)对象就是类的实体,是具体的实例
2)类就是用来产生对象的模板
3)只要看到有new才创建对象
在堆内存中创建了一个实例(对象),引用s1在栈内存中的存放该对象的内存地址
2、方法的递归
方法的递归:自己调用自己
3、垃圾回收机制
垃圾回收机制:
1)当没有引用指向的时候,该对象就会被当成垃圾被回收;
2)finalize()方法,垃圾回收线程;
3)Java虚拟机的回收机制是达到某一个空间容量就会执行;
4、构造方法
构造方法(构造器):
1)方法名和类名相同
public class xxx(){} 则其方法名为public xxx(){无参构造},public xxx(int a){有参构造}
2)没有返回值也没有void
3)一般用public来修饰
4)在Java中,每个类都至少要有一个构造器
5)当你新建的一个类中没有写构造方法时,其实编译器默认给你添加了无参的构造方法
6)当你的类中,有有参构造时,无参构造则消失
作用:
1)初始化对象,当构造方法执行完成时就完成了对象的创建
2)当你使用new创建一个对象时,调用对应的构造方法先完成对象的初始化工作,再将对象那个创建出来
3)一般用于给成员变量初始化
构造方法可以重载:
1)当你实例化一个对象时会默认调用无参构造方法
2)当你的类中有了一个有参的构造方法时,无参的构造方法就会被删除
3)一般我们在提供有参的构造方法时也会提供一个无参的构造方法
this关键字:
1)this()括号中的参数表示你调用了哪一个构造器 ,只能在代码的第一行
2)只能在本类的构造方法中
3)调用其它重载的构造方法
4)谁创建的对象this就是谁的
5、类图(课外知识)
注意: + 代表public - 代表 private # 代表 protected Animal代表类名
public class Animal {
public String name;
private int age;
protected String trueName;
String sex;
public String getName() {
return name;
}
private void setName(String name) {
this.name = name;
}
}
6、包名命名规范
包名命名规范:
1)在同一个包中,类不能同名
2)包允许将类组合成较小的单元
有助于避免命名冲突
包允许在更广的范围内保护类、数据和方法
3)若要使用到不在本包的类时,则需要导包import 包名.类名
4)将类放入包中,语法为:package 包名 ;
5)在java中位于包中的类,在文件系统中的存放位置,
必须有与包名层次相对应的目录结构
每个源文件只能声明一个包
java中的层次结构对应操作系统中的文件系统
6)Java类库中常用的包:
java.lang
Java默认包,任何程序中,该包都被自动导入。
java.io
输入/输出操作有用的类的组成。
7)[面试题]package语句作为java源文件的第一条语句 如果没有package语句,则默认为无名包java.lang不需要手动导入,任何时候jdk面向独享编程自动导入该包
7、构造代码块
8、静态代码块
public class Static {
int age;
static int price;
public Static() {
this(12);// 调用有参构造,无参构造器失效
{
System.out.println("构造代码块");
}
System.out.println("无参构造");
}
public Static(int age) {
this.age = age;
System.out.println("有参构造");
}
static {
price = 50;
System.out.println("静态代码块");
}// 静态代码块在类加载的时候就已经加载到内存了
public static void Static() {
System.out.println("静态方法");
}
public static void main(String[] args) {
Static s = new Static();
s.Static();//调用静态方法,又加载一遍
}
}
结果:
静态代码块
有参构造
构造代码块
无参构造
静态方法
构造代码块:永远放在对象实例化对应的构造器的第一行,会默认放上构造器中
成员代码块 :初始化成员
对象实例化的过程:静态代码块-->构造代码块-->构造方法
实例化多少个对象就调用多少次构造代码块
9、访问修饰符
访问修饰符可用于属性和方法
10、static关键字
static关键字 :静态在类中声明,属于类级别,静态资源在类加载的时候就被初始化了
static修饰变量:类变量(静态变量)
static修饰方法:类方法(静态方法)
调用方式:通过类名直接调用,也可以通过实例化过后的对象引用进行调用
注意:
1)静态方法不能修饰构造器 为什么?
由于static修饰的方法在类加载的时候就完成初始化工作,构造器时在创建对象的时候才调用
2)静态方法中不能使用this关键字
3)静态方法里只能直接访问静态属性和方法,而不能直接访问类中的非静态属性和方法
4)静态方法不能调用成员属性和成员方法 :因为成员方法在实例化之后才能被调用,而静态方法类加载时就完成初始化
static代码块:
1)静态代码块 --完成静态属性的初始化工作
2)类加载在实例化之前就已经完成了,并且类只加载一次,但是可以实例化多次
3)当jvm虚拟机运行时会找到该类对应的.class文件加载到内存中,会初始化静态资源,自动调
4)用静态代码块完成静态变量的初始化工作
5)静态代码块:在类加载的时候自动执行
成员变量:对象级别,只能实例化过后才能调用,在对象被创建时才初始化不属于某个对象,而是所有对象共享
成员方法:对象级别,只能实例化过后才能调用,在对象被创建时才初始化
静态方法:王室 王室不访问平民
成员方法:平民 平民访问王室
11、super关键字
super关键字:
1)super会默认添加在构造器的第一行,只能出现在子类的构造器中,且必须是第一行
2)super():父类的空的构造方法
3)super()和this()不能同时出现在一个构造器中
注意:
1)实例化子类时,会默认先调用父类的空的构造方法,如果父类中没有空的构造方法时就会编译出错
2)super()中的参数,决定了调用父类哪个构造器
3)构造器只有初始化对象的作用,没有创建对象的作用,只有看见new才会创对象,构造器执行完成时就是对象创建完成的标志
super和this关键字:
super. 指向父类的引用
1)通过关键字super我们可以指定子类在构造时调用父类的哪个构造器,达到先初始化父类然后实例化子类的目的。
2)子类的构造器默认的调用父类无参构造器,即子类构造器中没有用super指明调用父类哪个构造器的话,实际上编译器会自动的在子类构造器第一行加入代码super( );
this.指向本类的引用
1)我们知道子类在实例化时必须调用父类的构造器,实际上有的子类构造器也可以先调用本类的其他构造器,然后再通过那个构造器调用父类的构造器
2)无论是调用父类的构造器还是子类的构造器,最终都是找到最顶级的父类自上而下将父类初始化再实例化子类。只要中间环节有一个构造器没找到,这个子类就无法完成实例化。
12、单例模式
单例模式:
保证一个类在内存中只存在一个实例
1)提供一个私有构造器
2)提供一个私有的静态的自身属性的变量
3)提供一个静态的返回自身类型的方法--全局访问点 public
public class TestInstance {
private TestInstance() {
System.out.println("构造器");
}
//懒汉式
/*private static TestInstance testInstance;
public static TestInstance getInstance() {
if(testInstance==null) {
testInstance=new TestInstance();
}
return testInstance;
} */
//饿汉式
private static TestInstance testInstance=new TestInstance();
public static TestInstance getInstance() {
System.out.println(testInstance);
return testInstance;
}
public static void main(String[] args) {
//懒汉式
/* TestInstance t1=new TestInstance();
TestInstance t2=new TestInstance();
System.out.println(t1==t2);//false*/
//饿汉式
TestInstance