重载:相同函数名,不同参数。
重写(覆写):父类和子类之间的,子类重写了父类的方法。
java的多态:重载+覆写
1. Main方法:
是public的,也是static,也是void的,参数为String[] args.
之所以为static,是因为main方法不需要生成对象实例就可以由Java虚拟机来直接调用。
修改或者没有main函数,编译不会有错误,因为编译把main当做普通的函数来处理,但是运行有错误,因为运行的时候,Java虚拟机需要调用main函数而没有符合要求的这个main函数。
1).main函数是可以重载的。但是入口的main函数式唯一的,必须那样写。重载了之后,把其他的重载都当做普通的函数。
2).main函数可以被其他函数调用,但是程序入口必须为main函数
3).main函数是可以被继承的
4).父类定义main函数,子类定义main函数,那么子类里面隐藏了父类的main函数。
2.++运算符
输出结果为0
我们就觉得很奇怪,来分析++的运行机制
如果把i=i++改为i=++i,那么结果是1.
前置++比较好理解,后置++我们需要分析原理,后置++实际上是先把i的值保留,然后把i+1,然后用自增前i的值做运算。
首先我们要理解下面的程序的输出:
a之所以为0,就是因为,i++是用i增加前的值来进行运算的,但是i++这个动作,又是在运算前进行的。所以++这个运算符的优先级是高于赋值运算符“=”的。
3.对于整数的求余和整除,都需要确保分母不为0,否则会抛出异常。但对于浮点数则不会。
输出:
NaN=Not A Number(非数值)
Infinity:正无穷大,-Infinity:负无穷大
从上可以看出,不管是float还是double类型,如果被除数不为0而除数为0,那么就会得出Infinity,如果被除数为正,就是正无穷大,否则就是负无穷大(-Infinity),如果被除数为0,那么结果为非数值。
4. Java中定义了三种移位运算符:
左移运算符(<<)后面添0
右移运算符(>>)前面添最高位数,如果为正,最高位为0,如果为负,最高位为1
无符号右移运算符(>>>)前面最高位填充0
5.异或(^)
看程序
输出结果为x的值,也就是说x与某个数,异或两次,就还是原来本身,这个很重要。
所以,要交换x和y的值,但不能开辟新的变量,我们可以这样做:
X=x+y;//x是x和y的值的和
Y=x-y;//y是x的值
X=x-y;//x是y的值
但上面的方法会出现一个问题,就是x+y可能会溢出,从而得到不正确的结论。
所以现在利用上面的两次异或等于本身的方法,再来做一次。
X=x^y;
Y=x^y;// y=x^y^y=x;
X=x^y;// x=x^y^x=y;
通过这种方法,就不会有溢出的风险了。
5.数组默认值
1).基本数据类型的数组在创建之后,已经赋默认值0 (或0L、0.0D、0.0F)
2). 引用类型的数组在创建之后,已经赋默认值null.
6.指定数组长度的变量必须为int类型,所以下面出现了错误:
如果指定长度为负数,那么编译的时候不会报错,但运行时会报错。
7.数组的复制
看上面,上面的复制方法,aa和bb是指向同一个内存空间的,所以修改bb的值会影响aa的值。
所以不能用上面的复制方法。需要用下面的方法:System.arraycopy
但上面的copy方法只适合于两个数组类型相同,并且都是值类型,而不是引用类型(所谓引用类型,就是非值类型的都是引用类型)
8.访问修饰符
Public: 在同一个包或者不同包中都可以被访问,被继承,在任何位置都可见。
Protected:本包中可以继承和访问,外包中只能继承,不能访问。
默认(default或friendly):本包内可以访问和继承,外包不能访问和继承。
Private:除自身之外,谁也不能访问,也不能继承。
9.构造器
构造器不是方法,也不是类的方法成员,之类可以继承父类的方法,但不能继承父类的构造器,在子类新建子类实例的时候,会自动调用父类的构造器(正所谓没有父亲,哪有儿子,所以必须调用父类的构造器新建了父类,才能调用子类的构造器来新建子类),我们也可以显式的调用父类无参的构造器:Super();
如果super()显式的调用,必须为子类构造器中的第一句。所以,如果子类没有显式的调用父类构造器,而父类又没有无参的构造方法,就会产生编译错误。
父类 子类
父类没有无参数构造器,那么子类必须显式调用父类的构造方法。
那么如果父类的构造器声明为protected,那么外包的子类可以继承,但那个外包的子类在新建实例的时候,需要先调用这个父类的构造器,但没法调用,就没法新建外包子类的实例。
10.成员变量的默认值:
成员变量 |
默认值 |
Boolean |
False |
Byte |
0 |
Short |
0 |
Char |
空 |
Int |
0 |
Long |
0 |
Float |
0.0 |
Double |
0.0 |
引用类型 |
Null |
11.成员变量初始化
1).在声明时初始化
2).使用初始化块
3).使用构造器
静态成员初始化
1).在声明时初始化
2).使用静态初始化块
初始化顺序:
public classStudent {
private String name = ttName();
public String ttName()
{
System.out.println("变量直接初始化");
return "zhulei";
}
public static int ttAge()
{
System.out.println("静态变量直接初始化");
return 24;
}
public Student()
{
System.out.println("构造方法");
age=44;
}
{//初始化块
System.out.println("初始化块");
name="11";
age=22;
}
static{//静态初始化块
System.out.println("静态初始化块");
age=33;
}
private static int age=ttAge();
}
输出结果:
从上面可以看出,初始化首先是静态的,然后是非静态的,对于静态或者非静态,是按照先后顺序执行的,最后才是构造方法。对于静态,只会执行一次。
12.Java垃圾回收机制始终以一个较低的优先级的后台进程进行垃圾回收工作,但这个回收工作是不确定的,不知道什么时候执行,也有可能不执行。我们再用完某个变量的时候,尽量把他至空,那么就是建议垃圾回收回收它。
垃圾回收只会回收对象所占的内存资源,也就是使用new在堆上创建的对象。
在子类调用构造器的时候,会首先调用父类的构造器,但在执行finalize方法时,不会调用父类的finalize方法。因为清理的顺序和构造的顺序是相反的,那么如果先调用父类的finalize,那么父类没有了,哪有子类呢。
Finalize方法最多只会执行一次,有些时候可能不执行。
13. Java中final,finally和finalize的区别是什么?
final修饰符 修饰常量
finally 用于捕获异常的最后输出
finalize是垃圾回收机制里面的方法
14.==和equal的区别
==:是用来判断两个对象的地址是否相同,即是否是指相同一个对象。比较的是真正意义上的指针操作。
而equal的源码如下:
是用==实现的,所以其实没有任何区别的,但是,很多对象里面,比如String,都对equal进行重写,使得他不一样的地方是:用来比较两个对象内部的内容是否相等的。
Equal有五点特性:
1) 自反性:对任意引用值X,x.equals(x)的返回值一定为true.
2) 对称性:对于任何引用值x,y,当且仅当y.equals(x)返回值为true时,x.equals(y)的返回值一定为true;
3) 传递性:如果x.equals(y)=true,y.equals(z)=true,则x.equals(z)=true
4) 一致性:如果参与比较的对象没任何改变,则对象比较的结果也不应该有任何改变
5) 非空性:任何非空的引用值X,x.equals(null)的返回值一定为false
15.Java中的数据类型不是对象,用起来很方便,但有些时候,某些类(比如集合类)并不支持基本的数据类型,因此,Java中为每个基本数据类型都定义了一个包装类型,这样,在需要某个基本数据类型时,就可以使用它的包装类型。同时,Java中还提供了自动封箱和拆箱的功能。
包装类重写了equal方法,只要两个包装类对象说包含的基本数据类型数据是相等的,那么,则认为两个包装类对象是相等的。
基本数据类型和包装类型混合的时候,是全部装包,还是全部拆包呢?在进行==比较时,会将包装类拆箱为基本数据类型再进行比较。
16.子类继承父类
1).子类继承父类所有的public和protected成员,不论子类与父类是否在同一个包中
2).如果子类和父类在同一个包中,那么子类也会继承父类包中访问权限的成员
3).子类不能继承父类的私有成员,但可以通过父类的public或protected方法间接访问父类的私有成员
上转和下转
子类可以直接上转为父类,不需要强制转换标志,但不具备子类特有的特征,但还具备子类和父类所共有,而子类重新定义的特征。
子类上转为父类后,这个父类又可以下转为子类(但需要强制转换标志),普通的父类是不能下转为子类的,因为所有的猫是动物,但所有的动物不是猫。但由猫产生的动物还是猫。子类上转为父类后下转为子类后,还是具有子类特有的特征的。
输出结果:
我们可以看到,父类的构造方法,就调用了一次,虽然子类新建了两个实例,但父类构造方法只调用了一次。
我们再看一下这个程序:
输出结果:
如果存储是子类新建,那么只需要调用一次父类的构造方法就可以了。
我们再看:
输出结果:是一个父类的构造方法呢?还是两个父类的构造方法?
17.instanceof
一个实验结果,说明一切
父类不是子类,但由子类上转上来的父类是子类,所有的子类都是父类。
继承下的初始化顺序:
父类:Student
public classStudent {
private String name = ttName();
public String ttName()
{
System.out.println("student变量直接初始化");
return "zhulei";
}
public static int ttAge()
{
System.out.println("student静态变量直接初始化");
return 24;
}
public Student()
{
System.out.println("student构造方法");
}
{
System.out.println("student初始化块");
name="11";
age=22;
}
static{
System.out.println("student静态初始化块");
age=33;
}
private static int age=ttAge();
}
子类:StudentChild
public classStudentChild extends Student {
public StudentChild()
{
System.out.println("studentChild构造方法");
}
private static String course=ttCourse();
private int ttScore()
{
System.out.println("studentChild变量直接初始化");
return 50;
}
private static String ttCourse()
{
System.out.println("studentChild静态变量直接初始化");
return "chinese";
}
{
System.out.println("studentChild初始化块");
score=100;
}
static{
System.out.println("studentChild静态初始化块");
course ="english";
}
private int score=ttScore();
}
输出效果如下:
从上可以看出,先父类后子类,先静态后动态
18.子类重写或隐藏父类的方法
如果子类和父类名称,参数,返回值都相同,那么是重写,如果再加一个条件,都是静态方法,那么就是隐藏。
要想实现重写,还需要:子类方法的权限不能小于父类方法的权限,子类方法不能比父类方法抛出更多的已检测的异常。子类必须继承父类的方法。
将子类上转为父类,如果子类重写了父类的方法,那么通过父类的实例调用的是子类的方法,如果不是重写,那么通过父类的实例调用的是父类的方法。
父类:
输出结果:
Cry是非静态的,所以子类重写了父类,而run是静态的方法,所以子类隐藏了父类。
19.接口
接口中的变量默认是 public static final,是静态常量,通过类名直接调用,不能修改
接口中的方法默认是public abstract,不能用static,因为这个方法是需要被继承和实现的。
(abstract和static不能同时修饰方法)
标记接口---有些接口并没有声明任何方法,只是用来标记实现接口的类具备某些特殊的功能,比如java.io.Serializable.
接口只是设计,不是实现,所以可以实现多重继承,多个接口之间用”,”分割。
如果C继承了A,同时也继承了B,但A和B中有相同的常量,那么C中调用的时候,必须用类名来调用。
如果A和B中有相同的方法,包括参数和返回值,那么对于C来说,就是一个方法,因为接口没有方法体,所以,C只需要实现一个方法就可以了。
20.接口上转
用具体的类来新建接口,就是具体的接口上转。
21.接口的默认方法
接口中即使是空的,也是有方法的,那就是隐藏的默认方法。
22.接口和抽象类
接口与抽象类的异同点
[1].相同点:
<1>.二者都包含有描述系统能提供服务的抽象方法,都不提具体实现的方法体,都不能被实例化。
<2>.都位于继承树的上层,都代表系统的抽象层。当系统使用继承树上的类时,应尽量把引用变量声明为继承树的上层抽象类型,这样可以提高两个系统的松耦合程度。
[2].不同点:
<1>.抽象类中可以定义调用方法的方法体以免在子类中的重复定义,对子类中修改方法体不会造成影响;对于接口,一旦接口公布就必须保持稳定,因为随意向接口中添加方法会直接影响到子类的功能,此时子类要么实现新增的方法,要么就声明为抽象类,而声明为抽象类就意味着该类不能进行实例化,也就限制了该类的应用了。
<2>.一个类只能有一个直接父类(此父类可以是抽象类),但它可以实现多个接口。当子类覆盖父类的调用方法或隐藏父类的成员变量及静态方法时,Java虚拟机采用不同的绑定机制,为了简化系统设计的复杂性和绑定机制,Java禁止多重继承;对于接口,其内部只含有抽象方法而没有实例变量及静态方法,即便一个类实现多个接口也不会增加绑定机制的复杂性。
接口和抽象类的使用原则:
[1].使用接口作为系统与外界交互的窗口。
[2].接口必须保持稳定性。
[3].使用抽象类来定制系统中扩展点。
23.静态内部类
相当于类内的一个静态成员变量,不依赖于外部类的实例存在,静态内部类可以访问类内的所有成员,包括private成员。
24.内部类
内部类依赖于外部类而存在的。内部类必须要先创建类的对象,才能创建内部类。
静态内部类:
非静态内部类:
两种类的新建实例的方法:
25.局部类
局部类是在方法里面的类。
26.泛型
JAVA泛型? T K V E含义
?表示不确定的java类型,类型是未知的。
T 表示java类型。
K V 分别代表java键值中的Key Value。
E 代表Element,特性是枚举。
27.反射
Reflection 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性。
反射的作用可以总结为:通过类的方法,有两种:
Class c = Class.forName(packageName +"." + "A");
或Class c = Student.class;
来获得这个类,来反过来获取自己的一些信息。
java反射机制能够知道类名而不实例化对象的状态下,获得对象的属性或调用方法
28.String
String对象是不能改变的,所以对String的修改都是通过新建对象来进行的。