Java面试:基础概念
1,java语言是解释执行,java源码是通过编译生成一种特殊的.class的中间字解码文件,然后再有JVM进行解释执行。
2,java语言对指针进行了上层的封装,它保证能够通过这个指针(引用),来访问有效的内存单元。
3,java语言不允许多继承,使继承关系成树装图,每个类都只能有一个父类。
4,java语言的开发效率高,但执行效率低。(相当于c++的55%)
5,java的垃圾回收机制,在java中new的对象不需要向c++一样进行delete操作,JVM会根据情况回收垃圾对象。(懒汉机制,等待资源没有的时候才回收)我们只能够建议JVM进行垃圾回收,例如(System.gc() RunTime.gc()这两个方法就是建议JVM进行垃圾回收的方法)
6,JDK,java开发工具包(类库和运行命令),JRE,java运行环境,JVM,java虚拟机(解释执行的核心,对字节码进行翻译成运行环境的机器码,它可以屏蔽平台差异。JVM是不跨平台的。)
7,JAVA_HOME,指明JDK安装的位置,CLASSPATH,指明类文件的位置,PATH,指明命令的可执行文件的位置。
8,java源文件的文件名必须和文件中定义public class的类名(大小写页要相同)相同。
9,java源代码中的main方法的定义写法。main方法是程序的入口。
public static void main(String[] args){
System.out.println("Hello world");
}
10,java源文件也要先编译,使用javac xxx.java格式的命令得来编译,使用java xxx来运行。
11,定义包结构要放在有效代码的第一行,package xxx.xxx,包的定义在一个程序中只能由一个,在加上包定义之后编译可以使用javac -d 路径 xxxx.java,这个-d这个命令行的参数可以指定包结构的位置“.”代表当前目录。在运行时要使用类的全名
12,java xxx.xxx.xxxx用包名以点分隔。运行时要在包结构的上一层目录来运行。
13,java中的注释,
单行注释 //......
多行注释 /* .......*/
文档注释/** ........<p>(换行标签)*/,
用javadoc命令可以根据原码中的文档注释生成注释文档(html格式)。文档注释中可以使
用html标签。
javadoc -d 路径 (指定注释文档的保存路径)
文档注释一般写在类定义之前,方法之前,属性之前。
在文档注释中可以用 @author 表示程序的作者,@version 表示程序的版本,前两个注释
符号要写在类定义之前,用于方法的注释@param 对参数进行注释,@return 对返回值进行注
释 @throws对抛出异常的注释。
14,jar命令用于打一个xxx.jar文件
用法:jar {ctxu}[vfm0Mi] [jar-文件] [manifest-文件] [-C 目录] 文件名 ...
选项:
-c 创建新的存档
-t 列出存档内容的列表
-x 展开存档中的命名的(或所有的〕文件
-u 更新已存在的存档
-v 生成详细输出到标准输出上
-f 指定存档文件名
-m 包含来自标明文件的标明信息
-0 只存储方式;未用ZIP压缩格式
-M 不产生所有项的清单(manifest〕文件
-i 为指定的jar文件产生索引信息
-C 改变到指定的目录,并且包含下列文件:
如果一个文件名是一个目录,它将被递归处理。
清单(manifest〕文件名和存档文件名都需要被指定,按'm' 和 'f'标志指定的相同顺序
示例1:将两个class文件存档到一个名为 'classes.jar' 的存档文件中:
jar cvf classes.jar Foo.class Bar.class
示例2:用一个存在的清单(manifest)文件 'mymanifest' 将 foo/ 目录下的所有
文件存档到一个名为 'classes.jar' 的存档文件中:
jar cvfm classes.jar mymanifest -C foo/ .
一般在使用使用jar cvf 文件名.jar 文件所在路径(xxx/xxx/xxx.class)也可以压缩一
个目录,只要在制定路径是指定为文件夹,jar命令的命令行参数在使用时可以以“-”开头
,也可以不用。
15,java程序的运行过程,首先是启动java虚拟机,然后就是去找.class文件,先是从系统
的类库中找(系统之会在跟目录下查找,所以需要完整类名),如果找不到的话会去
CLASSPATH所设置的目录去找。然后加载到java虚拟机中。
系统会在每个java程序中隐含导入了java.lang这个包,import 包名,导入包中的类文件
。
java.lang包,这是一个基础包。
java.util包,这个包是工具类的包。
java.io包,这个包是用于输入输出操作的
java.net包,这个包是用于网络编程。
java.awt,java.swing,javax.swing java.event包,这些包用于java的图形编程用的包
。
applaction java的应用程序,java应用程序中必须有一个main()方法。
16,标识符和关键字
Java代码中的“;”、“{}”、“ ”
Java语句以分号分隔,Java代码块包含在大括号内,忽略空格。标识符
1) 用以命名类、方法和变量、以及包遵守JAVA的命名规范类以每个单词都以大写字母开头
。方法和变量第一个字母不大写,其他照旧。
2) 只能以字符、“_”或“$”开头;
3) 无长度限制。
java中的关键字
goto和const在java中虽然不再使用但是还作为关键字存在
java中没有sizeof这个关键字了,java中的boolean类型的值只能用true和false,且这两
值也是关键字。
java语言中没有无符号这个关键字(unsigned)
17,java中的数据类型
1) 整型
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
2) 浮点类型
float 4字节 32位
double 8字节 64位
3) 字符类型
char 2字节 16位
4) 布尔型
boolean false/true
注:1) char是无符号的16位整数,字面值必须用单引号括起来; ‘a’
2) String 是类,非原始数据类型;
3) 长整型数字有一个后缀为“L”或“l”,八进制前缀为“0”,十六进制前缀为
“0x”;
4) 黙认浮点类型为double;
5) float数据类型有一个后缀为“f”或“F”,Double数据类型后可跟后缀“D”或
“d“
6)char类型也可以用通用转译字符,但是不能用ASCII码。可以用“\u0000”这种
格式,因为char型中使用的是unicode编码方式。
注:整型值存放,正数存放原码(二进制码),负数则存放补码(原码按位取反末位加
一)。
注:实型值在存储时会损失精度,所以不要直接比较两个实型值。系统默认的实型都是
double型,要使用时要在数据后加个f,或者强行转换。强转(占字节数大的类型转到占字
节数小的类型)时会放弃高位值只取低位值。
18,java中的数字数据类型减灾由占字节数小的类型到占字节数大的类型的可以有自动转换
,反之则需要强行转换,char型和int型之间可以相互转换。char和short不能像户转换。
注意:隐式类型转换;
a 运算符 b ,如果a,b中有任意一个是double型,前面运算的结果就是double型,如果a
,b中有任意一个是float型,前面运算的结果就是float型,如果a,b中有任意一个是long
型,前面运算的结果就是long型,如果a,b中没有double、float、long型,那么其结果就
为int型。
所有基本数据类型在使用时会事先分配空间,只本身就存在空间中,在传递时,就是值传递
,不是引用传递。
----------------------------------------
在类中定义的方法在返回值前加上static修饰符就可以在main方法中调用了。如果不用
static那就需要在main方法中创建对象,使用对象来调用对象的方法。
public class Test{
public static void main(String[] args){
Test t=new Test();
int b=1;
int c=2;
int[] a=new int[10];
t.sqort(a);
add(b,c)
}
public int[] sqort(int[] a){
.......
}
static int add(b,c){
.......
}
}
java中的运算符(java的运算符的优先级和结合性和c++相同)
System.out.println(3/2) 按整型计算 得1
1) >>= 前面是零补零,前面是一补一;
2) >>>= 无符号右移(强制右移都会移进一),
>>=和>>>=对于负数不一样
正数:右移n位等于除以2的n次方
负数:变成正数。
3) && 短路与,前面为假,表达式为假,后面的操作不会进行,& 会对所有条件进行判断
。
4) || 短路或,前面为真,表达式为真,后面的操作不会进行,| 会对所有条件进行判断
。
例:
if(a<3&(b=a)==0) b赋值
if(a<3&&(b=a)==0) b不赋值
5)instanceof,是用于判断一个对象是否属于某个类型
6)java中的求余运算符“%”可以对两个实型变量求余
注:按位与是为了让某些位置一,按位或是令某些位置零,按位异或是令某些位取反。
注:使用左右位移和无符号右移运算符的使用方法是 变量名<<=位移位数 ,变量名>>=位移
位数 (前两个运算符是不会忽略整形符号位,也称逻辑位移),变量名>>>=位移位数
注意:左右位移和无符号右移运算符只能用于整形及其兼容类型(byte,int,short,long
)
注意:java程序的运行过程,首先是启动java虚拟机,然后就是去找.class文件,先是从系
统的类库中找(系统之会在跟目录下查找,所以需要完整类名),如果找不到的话会去
CLASSPATH所设置的目录去找。然后加载到java虚拟机中。如果要使用到其他的在
JAVA_HOME中没有的类或者是其他公司提供的第三方的.jar(jar包)文件时,要把它的路径
及文件名加到CLASSPATH中。
java的流程控制
控制流
if()
if()….else
if()…..else if()….else
注意:else只是和其上面的同层的最近的if()来配对。
switch(){
case 'a':……..
case 1:……break;
default:
…………
}
注解:switch()内数据类型为byte short char int类型,只有以上四种类型的才可以在
switch()中使用。case块中不加break时顺序执行下面的语句。
循环语句
for(int i=0;i<n;i++){}
while(){}
do{} while();-----------注意加分号
例子:
loop:for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(3==j){
break loop;//---------------loop为标签 只能用在循环语
句中,循环//嵌套中用于跳到外层循环
}
}
}
辨析:
int x,a=6,b=7;
x=a++ + b++; //----------a=7,b=8,x=13
int x=6;x=~x;//---------------- 6的二进制0110 取反得11001 再转成补码
(取反加一) 10111 = -7
break,跳出本层循环,执行后面的代码,continue,提前终止本次循环,再一次进行循环
或循环条件满足或不满足后退出循环。break 标签名; continue 标签名;这两条语句知
识表示跳出有标签的循环和提前终止本次有标签的循环,只能用在循环语句(多层循环嵌套
)中,循环嵌套中用于跳到外层循环。
注意:for循环在使用时一定要注意不要忘记()中的两个";",死循环的写法for(;;){}或者
是用
while(true){}
注意:System.out.println("..."+a)在使用这个语句时,它会将其中非字符串(String)
的值转换成字符串(不是所有数据类型都可以的)。
java中的数组Array,其包含两个部分,分别是数组的引用和数组的空间两部分。
声明数组
1) 一组相同类型(可以是类)数据的集合;
2) 一个数组是一个对象;
3) 声明一个数组没有创建一个对象;
4) 数组能以下列形式声明:
int[] i 或 int i[]
Car[] c 或 Car c[]
*C++中只能 Car c[]
*JAVA中推荐用 Car[] c;
5)数组的定义 如:
int[] a(数组引用声明)=new int[10](数组空间的声明,并把空间首地址赋值给
数组的引用)
int[] a;
a=new int[20];
创建数组
1) 创建基本数据类型数组 int[] i = new int[2];
2) 创建引用数据类型数组 Car[] c = new Car[100];
3) 数组创建后有初始值。
数字类型为0 布尔类型为false 引用类型为null
注意:访问没有初始化的数组中的值,是会抛出异常的(NULLpointerException),java中
只保证一位数组的地址是连续的,二维数组实际上是一维数组中有存储了一维数组的引用。
初始化数组
1) 初始化、创建、和声明分开
int[] i;
i = new int[2];
i[0] = 0;
i[1] = 1;
2) 初始化、创建、和声明在同一时间
int[] i = {0,1};
Car[] c = {new Car(),new Car()};
多维数组
1) 有效定义
int[][] i1 = new int[2][3]; (同时给定一维,二维的空间)
int[][] i2 = new int[2][]; (给定一维的空间,二维空间待定)
i2[0] = new int[2],i2[1] = new int[3];
*C++中 int[][] =new int[][3];有效
2) 无效定义
int[][] i1 = new int[][3];
3) 数组长度 ------------数组的属性length(在二维数组中这个属性只代表第一维的
长度)
int[] i = new int[5];
int len = i.length;//len = 5;
Student[][] st = new Student[4][6];
len = st.length;//len = 4;
len = st[0].length;//len = 6;
数组拷贝
System.arrayCopy(Object src, int srcPos, Object dest, int destPos, int
length);
src源数组,srcPos从第几位开始拷贝,dest目标数组,destPos目标数组放置的起始位置
,length,表示要拷贝的长度。
拷贝一个数组到另一个数组。
类的对象的创建和对象数组
一个xxx.Java文件中可以定义多个类但是只能由一个public修饰的类,也只能以这个类的类
名作为.java的文件名。
java中的类的对象的创建,要先创建这个对象的引用, 例如:Car c;然后用new这个关键
字创建一个对象的实例(对象的空间) 例如:c=new Car();,然后对象的实例的空间首地
址赋值给对象的引用。多个对象的引用可以同时引用自同一个对象的实例,但是对象的引用
只能引用一个对象的实例。
对象的引用和对象的实例间就像是牵着气球的线和气球一样。
注意:只有一个没有被任何对象的引用所引用的对象的实例才会边城垃圾等待被垃圾回收。
对象数组
例:Car[] c=new Car[3];
c[0]=new Car();
注意:存放基本类型的数组的数据是直接存放在数组的空间中,而对象的数组在数组空间中
存放的则是对象的引用。
定义在类中类的属性是实例变量,定义在类的方法中的变量是局部变量。实例变量是保存在
对象空间中的,而局部变量则是在方法调用的分配空间,调用结束后就释放空间。
注意:在类的定义中属性的定义和方法的定义 必须写在类里。
注意:系统会自动初始化实例变量,数字类型为0 ,布尔类型为false ,引用类型为null。
局部变量需要初始化,必须赋初值。如果不赋初值无法通过编译。
Java中的方法调用中参数传递有两种,一个是对于参数是基本类型的使用的是值传递(直接
传参数的值),另一个是引用传递,它是用于参数是类的对象,它传递的是这个对象的引用
。
----------------------------------------
面向对象的思想
anything is Object(万物皆对象)
抽象,从对具体的对象中抽取有用信息。
对象有其固有属性,对象的方法,即对象的行为(对象能做什么)
对象本身是简单的(功能简单),多个对象可以组成复杂的系统(对象之间彼此调用对方的
方法)
对象应当是各司其职(功能简单),各尽所能(把自己的功能作到最好)。(弱耦合性实现
了前面所述的对象的特点)
对象的耦合性,是对象之间的联系,对象和系统之间的联系。对象的耦合性要尽量的弱,也
就是对象之间的联系尽可能的弱,对象和系统之间的联系尽可能的弱。
系统的可插入性,是在系统中加入新的对象之后的系统稳定性。
对象的可替换性,是在系统中替换原有的对象之后的系统的稳定性。
复用性,即对象可否被重复使用,对象的功能越简单,复用性就越好。(对象的耦合性弱,
复用性就比较强)
面向过程是先有算法,后又数据结构(怎么解决问题)
面向对象是先有对象(数据结构),后有算法。(用什么做)
类是某些有着相同属性的集合的抽象。
类是一个类对象的模板,对象是类的具体化。
类是一个新的数据类型,类的对象。
注意:局部变量的作用范围是在定义他的代码块以内,局部变量要先赋值后使用,在以一个
重合的作用于范围内不允许两个局部变量命名冲突。局部变量局部优先,且在于实例变量同
名时会副该局部变量。
变量 包括简单变量(原始数据类型),对象变量。
方法的定义:
1,方法的修饰符(多个修饰符出现的顺序无关) |
2,方法的返回值类型 |顺
3,方法名 |序
4,方法的参数表 |向
5,方法中允许抛出的异常 |下
V
java中不能够在返回语句后写任何代码。JVM+解释器=JRE,JRE+类库=JDK
java中方法的重载(overload)方法名相同,参数表不同,返回值类型可以不同。调用时要
给出明确参数并确定调用某一方法。在编译时,编译器会根据参数选择适当的方法,所以重
载也叫编译时多态。
就近向上匹配原则
如果方法的参数表中的数据类型和调用时给出的参数类型不尽相同时会根据向上匹配的就近
原则。(类型就近向上转化匹配)
注意:调用时要给出明确参数并确定调用某一方法,否则编译会出错。
对象使用者(调用其他对象的方法)对象(对象中的方法被调用时根据参数进行自己进行选
择)
一类方法,但跟据不同的参数会有差异,对象回根据参数判断,对对象调用者透明。
创建对象的过程,1,分配空间 2,初始化属性 3,调用构造方法(有前提,不考虑继承关
系)
构造方法的写法,没有返回值类型,构造方法的方法命名必须和类名相同。如果在类中不写
构造方法,系统会提供一个无参的构造方法。
注意:最好在写类时提供一个无参的构造方法。
获得对象的方式
通过new(在堆空间中申请分配空间),new 类名(),可以通过这种形式或的一个对象,
这时的对象是无法使用,必须把的他的地址存放近一个对象变量才能够使用。例如 :Car
c=new Car();
有参的构造方法在被调用时,在用new关键字或的对象时初始化,例如:Car c=new Car
("yellow")
对象变量中存放的是对象的引用(地址的封装形式)
this关键字,表示当前对象(哪个对象调用了方法,哪个对象就是当前对象),可以用来区
分实例变量和局部变量。this(),他表示掉用本类其他的构造方法,注,只能写在构造方法
的第一行。
java中的参数传递,简单类型的变量传递的是数值,对象变量的传递则传递的一个引用(地
址)
----------------------------------------
面向对象的三大特征:封装、继承、多态。
java中的封装
封装,一个对象和外界的联系应当通过一个统一的接口,应当公开的公开,应当隐藏的隐藏
。(对象的属性应当隐藏),一个对象的内部是透明的,就是把对象内部的可透明性和隐藏
的特性区分开,该透明的透明,该隐藏的隐藏。
(封装的属性)java中类的属性的访问权限的默认值不是private,要想隐藏该属性或方法
,就可以加private(私有)修饰符,来限制只能够在类的内部进行访问。
对于类中的私有属性,要对其给出一对方法(getXxx(),setXxx())访问私有属性,保证对
私有属性的操作的安全性。
方法的封装,对于方法的封装,该公开的公开,该隐藏的隐藏。方法公开的是方法的声明(
定义),即(只须知道参数和返回值就可以调用该方法),隐藏方法的实现会使实现的改变
对架构的影响最小化。。
封装会使方法实现的改变对架构的影响最小化。
完全的封装,类的属性全部私有化,并且提供一对方法来访问属性。
java中的继承
继承,是对有着共同特性的多类事物,进行再抽象成一个类。这个类就是多类事物的父类。
父类的意义在于可以抽取多类事物的共性。
java中的继承要使用extends关键字,并且java中只允许单继承,也就是一个类只能有一个
父类。
这样就是继承关系呈树状,体现了java的简单性。
子类只能继承在父类中可以访问的属性和方法(实际上父类中私有的属性和方法也会被继承
但子类中无法访问罢了)。
访问控制修饰符:(可以修饰属性和方法)
private修饰符,表示只有本类内部可以访问。
default修饰符,方法不加修饰符,会默认为default,表示在同一个包中可以访问,父子类
在同一包中,子类可以继承父类的相应内容。(可以修饰类)
protected(保护)修饰符,表示同一包中可以访问,不同包的子类也可以访问继承。
public修饰符,表示公开,在任何地方都可以访问。(可以修饰类)
修饰符的权限是由上而下逐渐变宽的。
继承的意义,就在于子类可以在父类的基础之上对父类的功能进行发展,继承可以使系统的
耦合性降低,也就是使对象间的联系便的松散,使多类对象间的联系用其父类对象代替。
注意:构造方法不能被继承。
父类的属性及方法的确定:要从子类的角度来看子类间的共性,当所有子类都有这个属性时
,就应当考虑是否该放在父类中,方法也是如此,方法可以被看作是对象的行为,而类的方
法这时这一类对象所共有的行为,所以也应当在方法的确定时注意是不是所有的子类型中都
需要有这种方法,并且会根据不同的类型的行为的方式也不同才可以覆盖着个方法。
java中方法的覆盖
子类中有和父类中可访问(可继承到子类)的同名同返回类型同参数表的方法,就会覆盖从
父类继承来的方法。
注意:在jdk1.4以前要求方法的覆盖时,需要方法的返回值,参数表,方法名必须严格相同
,而在jdk1.5中方法覆盖,子类的中覆盖的方法的返回值可以是父类中被覆盖的方法的返回
值类型的子类型。
注意:子类的方法覆盖父类的方法时,方法的修饰符要么相同,要么子类中的方法的修饰符
表示的访问权限要宽于父类。父类中的私有方法,不能被继承到子类,就是说子类中即使将
其覆盖了也不会有多态。
覆盖的意义:对从父类中继承的方法的发展。
注意:父子类中有同名的属性不叫子类覆盖了父类的属性,这种情况较作属性的遮盖
(shadow)。
当构造有继承关系的对象的步骤
1,递归的构造父类的对象
2,分配空间
3,初始化本类实例变量(属性)
4,调用本类的构造方法
注意:子类对象中其实包含着父类的对象,也就是父类对象加上子类对象,才是完整的子类
对象的实例。
super关键字
super(),表示在子类的构造方法中调用父类的构造方法(可以通过这种方法在子类的构造
方法中初始化父类中的属性),super()也只能出现在构造方法的第一句上。super(),在子
类的构造方中指明构造父类时调用哪一个父类的构造方法构造父类。
super,这里所表示的是一个父类的对象,可以通过super来使用父类中可以访问的方法(可
以在父类中定义setXxx(),getXxx()方法来访问父类中的私有属性),super可以屏蔽父子
类中同名属性的冲突。
注意:在写类的时候,一定要写默认无参的构造方法,如果一个构造方法的第一句既不是
this(),也不是super()时,那么就会在这里隐含的调用他的父类的无参的构造方法,即隐含
的有super()。
少覆盖原则:既子类应当尽量少的覆盖父类方法,如果覆盖了父类的大多数方法,那就应当
考虑是否应当有继承关系
java中的多态(以子类覆盖了父类的方法为前提)
多态,把子类对象主观的看作是其父类型的对象,那么父类型就可以是很多种类型。
多态,编译时多态(方法的重载)
运行时多态(多态)
编译时类型,也就是可以被看作的类型,主观认定。
运行时类型,也就是实际的对象实例的类型,客观不可改变(也是被看作类型的子类型)
对于一个对象来说,在对象产生时,运行时类型就已经确定不会再改变,编译时类型可以和
运行时类型不同。在对象变量声明时可以确定其运行时类型,但是编译时类型对象变量背后
所指向运行时类型则可以是其本类型或者是其子类型。
多态三特性
1,对象实例确定则不可改变(客观不可改变)
2,只能调用编译时类型所定义的方法。
3,运行时会根据运行时类型去调用相应类型中定义的方法。
多态的意义:在需要使用一类对象的共性时,可以用多来屏蔽掉其子类中的差异。
注意:类的属性是没有多态的,只会根据编译时类型访问。只有子类覆盖了父类的方法,且
把子类对象党作父类类型来看时才会有多态。要注意区分子类中的方法重载。对于方法的重
载,则是会使用编译时类型来进行相应的方法调用。
两种复用
白箱复用,也就是继承复用,父类中的可以被子类访问到的就可以被继承,这样会有些不需
要的内容被继承下来,所以这种方式不太好。
黑箱复用,也叫组合复用,也就是把要复用代码的类的对象作为本类中的一个属性,然后再
通过方法的委托来实现由选择的复用,方法的委托就是在本类的方法内部通过该类的对象调
用要使用类的方法。
注意:尽量用组合复用替代继承复用。
多态的使用
多态用于参数,可以在方法的参数中传入其父类类型,在运行时会根据实际的运行时类型来
在方法中进行相应的操作。
多态用于返回值,可以在方法的返回值类型上是用其实际返回值的父类型,在使用期返回值
时也不比关心其实际类型。
多态可以使代码变得更通用,以适应需求的变化。也就是定义在父类中的方法,可以在子类
中有不同的实现将其覆盖,在为父类型的对象变量赋值相应需要功能的子类的对象实例。
----------------------------------------
java中的修饰符
static 表示静态,它可以修饰属性,方法和代码块。
1,static修饰属性(类变量),那么这个属性就可以用 类名.属性名 来访问,也就是使这
个属性成为本类的类变量,为本类对象所共有。这个属性就是全类公有。(共有的类变量与
对象无关,只和类有关)。
类加载的过程,类本身也是保存在文件中(字节码文件保存着类的信息)的,java会通过
I/O流把类的文件(字节码文件)读入JVM(java虚拟机),这个过程成为类的加载。JVM
(java虚拟机)会通过类路径(CLASSPATH)来找字节码文件。
类变量,会在加载时自动初始化,初始化规则和实例变量相同。
注意:类中的实例变量是在创建对象时被初始化的,被static修饰的属性,也就是类变量,
是在类加载时被创建并进行初始化,类加载的过程是进行一次。也就是类变量只会被创建一
次。
2,static修饰方法(静态方法),会使这个方法成为整个类所公有的方法,可以用类名.方
法名 访问。
注意:static修饰的方法,不直接能访问(可以通过组合方式访问)本类中的非静态
(static)成员(包括方法和属性),本类的非静态(static)方法可以访问本类的静态成员
(包括方法和属性),可以调用静态方法。静态方法要慎重使用。在静态方法中不能出现
this关键字。
注意:父类中是静态方法,子类中不能覆盖为非静态方法,在符合覆盖规则的前提下,在父
子类中,父类中的静态方法可以被子类中的静态方法覆盖,但是没有多态。(在使用对象调
用静态方法是其实是调用编译时类型的静态方法)
注意:父子类中,静态方法只能被静态方法覆盖,父子类中,非静态方法只能被非静态方法
覆盖。
java中的main方法必须写成static的,因为在类加载时无法创建对象,因为静态方法可以不
通过对象调用
所以在类的main方法。所在在类加载时就可以通过main方法入口来运行程序。
注意:组合方式,就是需要在方法中创建一个所需要的对象,并用这个对象来调用任意所需
的该对象的内容,不会再受只能访问静态的约束。
3,static修饰初始代码块,这时这个初始代码块就叫做静态初始代码块,这个代码块只在
类加载时被执行一次。可以用静态初始代码块初始化一个类。
动态初始代码块,写在类体中的“{}”,这个代码块是在生成对象的初始化属性是运行。这
种代码块叫动态初始代码块。
类在什么时候会被加载,构造(创建)对象时会加载类,调用类中静态方法或访问静态属性
也是会加载这个静态方法真正所在的类。在构造子类对象时必会先加载父类,类加载会有延
迟加载原则,只有在必须加载时才会加载。
final修饰符,可以修饰变量,方法,类
1,final修饰变量
被fianl修饰的变量就会变成常量(常量应当大写),一旦赋值不能改变,(可以在初始化
时直接赋值,也可以在构造方法里也可以赋值,只能在这两种方法里二选一,不能不为常量
赋值),fianl的常量不会有默认初始值,对于直接在初始化是赋值时final修饰符常和
static修饰符一起使用。
2,final修饰方法,被final修饰的方法将不能被其子类覆盖,保持方法的稳定不能被覆盖
。
3,final修饰类,被final修饰的类将不能被继承。final类中的方法也都是final的。
注意:final,不能用来修饰构造方法,在父类中如果有常量属性,在子类中使用常量属性
时是不会进行父类的类加载。静态常量如果其值可以确定,就不会加载该类,如果不能确定
则会加载该常量所在的类。
不变模式,对象一旦创建属性就不会改变。用final修饰属性,也用final修饰类(强不变模
式),用final修饰属性(弱不变模式)。
不变模式的典型体现:java.lang.String类,不变模式可以实现对象的共享(可以用一个对
象实例赋值给多个对象变量。)
池化的思想,把需要共享的数据放在池中(节省空间,共享数据)
只有String类可以用“”中的字面值创建对象。在String类中,以字面值创建时,会到Java
方法空间的串池空间中去查找,如果有就返回串池中字符串的地址,并把这个地址付给对象
变量。如果没有则会在串池里创建一个字符串对象,并返回其地址付购对象变量,当另一个
以字面值创建对象时则会重复上述过程。
如果是new在堆空间中创建String类的对象,则不会有上述的过程。
String类中的intern()方法会将在堆空间中创建的String类对象中的字符串和串池中的比
对,如果有相同的串就返回这个串的串池中的地址。
不变模式在对于对象进行修改,添加操作是使相当麻烦的,他会产生很多的中间垃圾对象。
创建和销毁的资源的开销是相当大的。
String类在字符串连接时会先的效率很低,就是因为它所产生的对象的书性是不能够修改的
,当连接字符串时也就是只能创建新的对象。
对于很多的字符串连接,应当使用StringBuffer类,在使用这个类的对象来进行字符串连接
时就不会有多余的中间对象生成,从而优化了效率。
abstract(抽象)修饰符,可以修饰类和方法
1,abstract修饰类,会使这个类成为一个抽象类,这个类将不能生成对象实例,但可以做
为对象变量声明的类型,也就是编译时类型,抽象类就像当于一类的半成品,需要子类继承
并覆盖其中的抽象方法。
2,abstract修饰方法,会使这个方法变成抽象方法,也就是只有声明(定义)而没有实现
,实现部分以";"代替。需要子类继承实现(覆盖)。
注意:有抽象方法的类一定是抽象类。但是抽象类中不一定都是抽象方法,也可以全是具体
方法。
abstract修饰符在修饰类时必须放在类名前。
abstract修饰方法就是要求其子类覆盖(实现)这个方法。调用时可以以多态方式调用子类
覆盖(实现)后的方法,也就是说抽象方法必须在其子类中实现,除非子类本身也是抽象类
。
注意:父类是抽象类,其中有抽象方法,那么子类继承父类,并把父类中的所有抽象方法都
实现(覆盖)了,子类才有创建对象的实例的能力,否则子类也必须是抽象类。抽象类中可
以有构造方法,是子类在构造子类对象时需要调用的父类(抽象类)的构造方法。
final和abstract,private和abstract,static和abstract,这些是不能放在一起的修饰
符,因为abstract修饰的方法是必须在其子类中实现(覆盖),才能以多态方式调用,以上
修饰符在修饰方法时期子类都覆盖不了这个方法,final是不可以覆盖,private是不能够继
承到子类,所以也就不能覆盖,static是可以覆盖的,但是在调用时会调用编译时类型的方
法,因为调用的是父类的方法,而父类的方法又是抽象的方法,又不能够调用,所以上的修
饰符不能放在一起。
抽象(abstract)方法代表了某种标准,定义标准,定义功能,在子类中去实现功能(子类
继承了父类并需要给出从父类继承的抽象方法的实现)。
方法一时间想不到怎么被实现,或有意要子类去实现而定义某种标准,这个方法可以被定义
为抽象。(abstract)
模板方法模式
用abstract把制订标准和实现标准分开,制定的标准就是模板,实现就是按模板标准来实现
,也就是继承模板,实现模板中相应功能的方法。模板中不允许修改的方法可以用fianl来
修饰,这个方法不能使抽象方法,为保证安全,封装,把模板中不公开的部分用protected
(保护)修饰。
----------------------------------------
java中的接口
接口是一种程序结构,是特殊的抽象类。接口中的方法必须都是公开的抽象方法(public
abstract),接口中的属性都是公开静态常量(public static final)。
声明一个接口用 interface 关键字,接口也是一种类型,编译之后也有生成相应字节码,他
的声明规范也要符合类型的定义(一个源文件中只能有一个public interface,接口名和源
文件名相同,有public interface,就不能在写public class了)。接口中的属性可以不加
修饰符,方法也不用加修饰符。
接口也可以继承,但是只能由接口继承,在用类去继承时要换用 implements 关键字,这时
类和接口也不叫做继承关系,而是实现关系,但其实质也是继承。
一个类可以继承也只能继承另外一个类,但是可以实现多个接口,其语法是在implements后
面写接口名,多个接口以“,”分隔。
接口之间是可以多继承的,其语法和类的继承语法是相同的,在接口多继承时,在extends
后写接口名如果要继承多个接口,接口名以“,”分隔,接口的继承关系只是把其父接口中
的抽象方法继承到子接口中。要实现接口就必须实现接口中的所有方法。
一个类可以在继承一个类的同时,也可以实现一个或多个接口。采用接口就绕开了单继承限
制。
接口类型也可以做为编译时类型使用,但其实际的运行时类型必须是完全实现接口的类的对
象实例,这样就使多态变得很灵活了,
注意:实现接口时,在实现(覆盖)抽象方法时,注意必须要在方法的返回值类型前加public
修饰符。如果没有完全实现接口中的方法,那么这个类就只能够是个抽象类,不能创建对象
。接口的是实质就是特殊的抽象类。接口没有构造方法。
接口的意义:
1,接口可以实现多继承。
2,用接口可以实现混合类型(主类型,副类型),java中可以通过接口分出主次类型。主
类型使用继承,副类型,使用接口实现。
3,接口进一步深化了标准的思想,接口本身就是一个标准,他起到了降低耦合性的作用,
接口可以使方法的定义和实现相分离,也就是将接口的定义者和实现者相分离,接口也可以
用于降低模块间或系统间的耦合性。针对接口编程可以屏蔽不同实现间的差异,看到的只是
实现好的功能,
接口:定义标准,
接口的实现:实现标准
接口的调用者:标准的使用
针对接口编程原则,也就是按照标准实现。
先有接口的定义,再有接口使用者,最后把接口的是先对象传入接口的使用者中,接口的使
用者会通过接口来调用接口实现者的方法。
接口的定义者定义好了标准,接口的使用者先写好了使用代码,接口的实现者写好实现之后
把实现对象传入接口的使用者中。他调用接口中方法也就是掉用接口实现中的方法。这种过
程叫做接口的回调。
尽量使用接口类型作为编译时类型,尽量将抽取到的共性行为写在接口中。
用若干个小接口取代一个大接口。(接口隔离原则)
把一个类的功能作成接口,只暴露想暴露的方法,接口隔离原则可以实现更高层次的封装,
针对的对象不同,暴露的方法也不同。
java中的根类Object
java中所有的类的父类或直接或间接的或隐含的都是Object类。
java不允许循环继承,也就是互相继承是不可以的。
Object类中的finalize()一个对象被垃圾收集的时候, 一个对象被垃圾收集的时候,最后
会由JVM调用这个对象的finalize方法
Object类中有一个String toString()方法,返回该对象的字符串表示。Object类中的
toString()方法他返回的是类名加上他的地址的一个字符串。在子类中推荐覆盖toString
()方法。
Object类中的boolean equals(Object o)方法是用来比较对象的内容是否相等,其返回值
是boolean类型的值,相同为真,不同则为假。实际上还是比较对象地址是否相同。String
类覆盖了equals()方法,他比较是对象中的内容是否相同。子类中也推荐覆盖Object类中继
承的equals()方法
equals()的覆盖原则,
自反性 x.equals(x) 为true
对称性 y.equals(x) 和 x.equals(y) 的值要相同,要么都为true,要么都为false。
传递性 x.equals(y)为true, y.equals(z)也为true ,那么x.equals(z)一定也为true。
覆盖equals()方法的步骤
boolean equals(Object o){
if(this==o) return true;//1,看看是不是一个对象
if(o==null) return true;//2,看看对象是不是空
if(!(o instanceof 本类类名)) return false;//看看是不是本类对象
......//根据本类设计。
}