1.构造器与初始化
创建对象时,如果没有显性的创建构造器,则jvm会创建一个默认的无参构造器,如果创建了构造器,那么jvm将不在创建构造器。
构造器:与类名相同,无返回值。
public class Construct {
public static void main(String[] args) {
Rock r = new Rock();
Rock1 r1 = new Rock1();
Rock2 r2 = new Rock2(11);
}
}
//默认构造器
class Rock {}
//手动添加无参构造器
class Rock1 {
public Rock1() {
System.out.println("无参构造");
}
}
//有参构造器
class Rock2{
public Rock2(int i){
System.out.println(i);
}
}
2.方法重载
方法重载:指方法名相同,参数列表不同。如有参构造与无参构造,即为方法重载。不能以返回值区分是否为重载方法。
2.1基本类型的方法重载:
所传参数类型与方法类型相同,则调用与之匹配的方法。
所传参数类型小于方法中参数类型,则匹配与之容量最近的方法,char类型比较特殊,char类型作为参数传递,会默认提升为int类型
所传参数类型大于方法中参数类型,则需将所传参数类型进行强制转换,否则编译不通过。
3.this关键字
如果想在方法内部获得当前对象可使用this关键字,this关键字只能存在于方法内部,表示当前对对象的引用。
3.1 方法内部调用this:可以直接return this返回当前对象
3.2 构造函数调用
public class Flower {
public static void main(String[] args) {
Worker wk = new Worker("玫瑰",999);//输出结果,先输出"无花之人",在输出"采了999花",最后输出"采了999玫瑰花"
}
}
class Worker{
Worker(){
System.out.println("无花之人");
}
Worker(int i){
this();
System.out.println("采了"+i+"花");
}
Worker(String name,int i){
this(i);
System.out.println("采了"+i+name+"花");
}
}
调用构造函数时,会根据this()传递的参数,自动匹配含有对应参数的构造函数。
4.static关键字
static修饰静态变量或方法,在创建对象前就已经被创建,且只存在一份,不能调用非static修饰的变量或方法,不存在this关键字,不需要创建对象。
5.清理及垃圾回收。
5.1finalize的用途,一旦垃圾回收准备好释放对象占用的存储空间,将首先调用finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象点用的内存。
public class FinizeTest {
public static void main(String[] args) {
new FinalizeCase();
System.gc();
}
}
class FinalizeCase{
protected void finalize() throws Throwable {
super.finalize();
System.out.println("执行了垃圾回收");
}
}
重写finalize方法,调用父类的finalize(),当只是通过new FinalizeCase()创建对象时,并没有引用指向对象,此时等着垃圾回收来回收此对象,但是垃圾回收发生是不定时的,无法控制,故我们通过调用System.gc()方法强制进行垃圾回收,通过输出可以看到,finalize()方法执行了。所以我们不能全指望垃圾回收处理,当某些必须关闭回收的对象,我们可以自己书写代码进行关闭。
5.2 垃圾回收原理
其它系统中的垃圾回收:每个对象者含有一个引用计数器,当对象有引用连接时,引用计数器加1,当对象无引用连接时,则计数器减1,直至减少为0,则该对象就将会被回收。
java虚拟机采用一种更自适应的垃圾回收技术,对于查找活的对象,通过停止-复制、标记-清扫方法进行。
标记-清扫:指从堆栈和静态存储区出发,遍历所有的引用,进行找出所有存活的对象,每当找到一个存活的对象,就会给对象进行一个标记,这个过程不会对回收任何对象,只有全部标记工作完成的时候,清理动作才会开始,在清理过程中,没有标记的对象不会被复制,直接释放空间,所以剩下的堆空间是不连续的,如果要得到连续的空间,则需要进行重新整理。
停止-复制:指拉圾回收器进行工作时,程序将停止运行,然后将活的对象复制到另一片区域中去,且按顺序进行排列,将变量引用指向新地址,此种方法复制需要更大的内存区域,效率比较低下。
6.成员初始化
对象中成员初始化:如果存在静态变量,则先初始化静态变量,然后初始化成员变量,在进行构造函数初始化。如果存在继承关系,首先初始化父类静态变量,在初始化子类静态变量,在初始化父类成员变量,在进行父类构造函数初始化,在初始化子类成员变量,子类构造函数初始化。
1.成员初始化
public class OrderInitialization {
public static void main(String[] args) {
House house = new House();//输出首先执行属性初始化,即先创建窗户1,然后在窗户2,在窗户3,在执行构造函数
}
}
class Window{
Window(int i){
System.out.println("window:("+i+")");
}
}
class House{
Window w1= new Window(1);
House(){
System.out.println("this is house");
Window w3 = new Window(3);
}
Window w2 = new Window(2);
Window w3 = new Window(3);
}
2.静态数据实始化
静态数据实始化:先执行静态成员变量实始化,且静态成员只会执行一次,在执行实例化成员,在执行构造函数。
3.显示静态实初始化
多个含有static关键字的子名:静态成员,静态块执行根据书写顺序执行,且一旦静态成员被访问,则其它静态成员同样会被初始化。
public class StaticInit {
public static void main(String[] args) {
Table table = new Table();
System.out.println("***************");
Table table1 = new Table();
/** 输出如下,静态成员只执行一次
cup(1)
cup(2)
cup(3)
table
cup(33)
***************
cup(3)
table
cup(33)
* */
}
}
class Cup{
Cup(int i){
System.out.println("cup("+i+")");
}
}
class Table{
static Cup cup1 = new Cup(1);
Cup cup3 = new Cup(3);
Table(){
System.out.println("table");
cup3 = new Cup(33);
}
static Cup cup2 = new Cup(2);
}
4.初始化块,对象中通过{}包裹需要执行的方法,每创建一个对象 ,就会执行一次初始化块中代码
public class InitBlock {
private String name;
private String price;
{
System.out.println( "name = 华为");
System.out.println( " price=4000");
}
public static void main(String[] args) {
InitBlock ib = new InitBlock();
InitBlock ib1 = new InitBlock();
/**输出
name = 华为
price=4000
name = 华为
price=4000
*/
}
}
5.父子类初始化顺序
public class FatherAndSonInit {
public static void main(String[] args) {
Son son = new Son();
}
//父子类初始化顺序,父类static,子类static,父类成员实始化,父类构造函数,子类成员初始化,子类构造函数
/**输出结果
* father static:Peple--父类静态
* Son static:Peple -- 子类静态
* father man :man -- 父类成员变量
* father --父类构造函数输出
* Son man:man -- 子类成中变量
* Son -- 子类构造函数输出
*/
}
class Peple1{
Peple1(String s){
System.out.println(s+":Peple");
}
}
class Man{
Man(String s){
System.out.println(s+":man");
}
}
class Father{
static Peple1 p1 = new Peple1("father static");
Father(){
System.out.println("father");
}
Man m = new Man("father man ");
}
class Son extends Father{
static Peple1 p1 = new Peple1("Son static");
Son(){
System.out.println("Son");
}
Man m = new Man("Son man");
}
7.数组初始化
public static void main(String[] args) {
int[] i = new int[6];
String[] s = new String[]{"one","tow","three"};
double[] d = {1d,2d,3d,4d};
for (int i1 : i) {
System.out.println(i1);//第一种方式创建,未给初始值,默认为0,如果引用类型,则默认为null
}
}
数组中存入的是对象的引用,如果存入的是基本数据类型,则对应的会得到基本数据类型对应的初始值。
8.可变参数
public static void main(String[] args) {
testVar(new String[]{"one","tow","three"},13,new Integer[]{1,2,3,4,5});
}
public static void testVar(Object... args){
for (Object arg : args) {
System.out.println(arg);
}
}
可变参数的基本形式为(数据类型... args),表示传递不定多个形式参数,如果需要传递固定多个形式参数,则需要将固定的形式参数放至参数前边。
9.枚举
public enum EnumTest {
NOT,MILD,MEDIUM,HOT,FLAMING;
public static void main(String[] args) {
//可以直接调用
System.out.println(EnumTest.FLAMING);
//可以获得其下标和具体的内容
for (EnumTest enumTest : EnumTest.values()) {
System.out.println(enumTest.ordinal()+":"+enumTest);
/** 输出
0:NOT
1:MILD
2:MEDIUM
3:HOT
4:FLAMING
*/
}
}
}
基本用法如上,可以定义某些常量,然后直接调用其结果
用法二:
public enum EmunCalss {
BEIJIN("001"),SHANGHAI("021"),GUANGDONG("020"),CQINGQING("023");
private String value;
EmunCalss(String value){
this.value = value;
}
public static void main(String[] args) {
for (EmunCalss emunCalss : EmunCalss.values()) {
System.out.println("name:"+emunCalss.name()+", value:"+emunCalss.value);
}
/**输出,定义的前边部位为name,可以在枚举中定义一个变量,得其值
name:BEIJIN, value:001
name:SHANGHAI, value:021
name:GUANGDONG, value:020
name:CQINGQING, value:023
*/
}
}