这里的主要内容是
初始化
相关的内容,其中还会穿插其他的内容
- 构造器初始化
- 静态数据初始化
- 显示的静态初始化
- 非静态实例初始化
穿插内容
- 构造器
- 方法重载
- this关键字
- static 关键字
构造器
构造器是在创建对象时被调用的特殊方法。(构造器是一个方法只不过它是特殊的),之所以特殊是因为构造器没有返回值。与返回空(void)不同。一个简单的说法,普通方法就算是void,还是可以掉的,但构造器没得改。构造器是一个静态的方法,
构造器中的方法名与它所在的类名相同。这是因为为了让编译器能够知道该调用那个方法。在创建对象时,编译器将为对象分配存储空间,并调用相应的构造器,这保证了你在操作对象之前,恰当的初始化了。
public class Apple { // 默认构造器 Apple(){ System.out.println("Hello Word"); } } class Test{ public static void main(String[] args){ Apple apple = new Apple(); } }
没有参数出入的构造器叫默认构造器,术语是无参构造器,有参数的叫有参构造器。
public class Apple { //有参构造器 Apple(String a){ System.out.println(a); } } class Test{ public static void main(String[] args){ Apple apple = new Apple("Hello Word"); } }
如果 Apple(String)
是类里唯一一个构造器,那么你在创建对象时必须传入参数。
注意:在java中初始与创建是捆绑在一起的,二者不能分离
默认构造器在没有其它的构造器时,编译器会自动创建一个默认构造器,如果类中有了构造器(无论是否有参数),编译器就不会自动创建了。如果没有构造器,就无法创建对象。
像下边这么写就会编译器会报错,因为 编译器没有找到 new Apple();
没有参数的构造器
public class Apple { Apple(String a){ System.out.println(a); } public void t(){ return; } } class Test{ public static void main(String[] args){ Apple apple = new Apple(); } }
像下边加一个无参构造器即可。
public class Apple { Apple(){ System.out.println("Hello Word"); } Apple(String a){ System.out.println(a); } public void t(){ return; } } class Test{ public static void main(String[] args){ Apple apple = new Apple(); } }
在上边的 Apple
类中,两个构造器它们名字相同,传入的参数不同,这种写法叫 方法重载
,在普通方法中也同样适用
方法重载就好比相同的词可以表达不同的含义,重载方法名字要相同其中一个重要原因是因为构造器,的名字要与类名相同,这样只有一个构造器名,就可用多种方式创建一个对象。普通方法的重载也和构造器一样。
public class Apple { /* 重载构造器 */ Apple(){ } Apple(String name){ } Apple(String name, Integer num){ } Apple(Integer num, String name){ } /* 重载的方法 */ /** * 获取苹果 */ public void getApple(){ } /** * 获取特定品种的苹果 * @param type 品种 */ public void getApple(String type){ } /** * 获取特定品种,即某一数量的苹果 * @param type 苹果品种 * @param num 苹果数量 */ public void getApple(String type, Integer num){ } /** * 获取特定品种,即某一数量的苹果 * @param num 苹果品种 * @param type 苹果数量 */ public void getApple(Integer num, String type){ } }
java区分方法名相同的方法,是根据每个方法的独一无二的参数列表去区分的。
如下这种情况虽然java允许 ,也最好不要用,因为会使得程序难以维护
Apple(String name, Integer num){ } Apple(Integer num, String name){ } /** * 获取特定品种,即某一数量的苹果 * @param type 苹果品种 * @param num 苹果数量 */ public void getApple(String type, Integer num){ } /** * 获取特定品种,即某一数量的苹果 * @param num 苹果品种 * @param type 苹果数量 */ public void getApple(Integer num, String type){ }
拓展:java为什么不用返回区重载方法。
有的时候并不需要一个方法返回东西,只需要方法本身的作用。
public void test(){ a(); } public void test(String name){ b(name); }
this关键字只能在方法内部使用,表示“调用方法的那个对象”。比如在Apple类的后一个方法中使用了this,this代表的就是Apple类。
public class Apple { public void getApple(){ } public void juice(){ this.getApple(); } }
注意:在上边的 juice() 方法中有调用,同一个类中的方法 getApple() ,在这里是没有必要加 this的,因为编译器会自动帮忙加上。虽然手动加也可以,不过高级语言之所以高级,其中一个原因就是它可以帮助我们省略一些重复的事情。
只用当需要指明当前对象时才需要使用 this
public class AppleNum { private int appleNum = 0; public AppleNum sumAppleNum(){ appleNum ++; return this; } public void print(){ System.out.println("总和:" + appleNum); } public static void main(String[] args) { AppleNum appleNum = new AppleNum(); appleNum.sumAppleNum().sumAppleNum().sumAppleNum().print(); } }
如上代码 sumAppleNum() 方法返回的 appleNum 对象的引用,从而使得可以循环调用 sumAppleNum() 方法。
this 可以有参数列表用于构造器调用构造器,构造器不能使用方法名调用构造器,也不能在普通方法普通方法中。在同一个构造其中 this只能调用一个构造器。
AppleNum(){ this("a"); } AppleNum(String type){ this(3); } AppleNum(Integer i){ } public AppleNum sumAppleNum(){ // this(3) 编译器会报错 }
如果类中的基本类型字段没有初始化,那java会为他们赋上默认值
public class Apple { boolean t ; char c; byte b; short s; int i; long l; float f; double d; Apple apple; public void get(){ System.out.println(t); System.out.println(c); System.out.println(b); System.out.println(s); System.out.println(i); System.out.println(l); System.out.println(f); System.out.println(d); System.out.println(apple); } public static void main(String[] args) { Apple apple = new Apple(); apple.get(); } }
从上边代码可以看出,基本类型变量没赋值,java会默认赋上初始值。对象赋上 null
,初始化的顺序,影响着程序的正确性。
除非用 new 创建对象,否则实际上并未获得任何对象。如果不想创建对象也能调用某一方法或属性,就可以使用static 关键字。当声明一个事物是 static
时,就意味着这个域或方法不会它所在的类的对象实例关联在一起。
static关键字
加上了 static
关键字,即为静态成员变量。
public class Apple { static int i = 1; public static void get(){ } public static void main(String[] args) { Apple.get(); int num = Apple.i; } }
上边展示了 static 关键字的基本用法,不用 new 对象也可以调用方法,虽然不用创建对象也可以调用方法,并不是说每个方法都加上 static
, 如果你的代码是这样,那你就得考虑一些你代码的设计问题了。
下边是加了 static
,与没加 static
的区别
public class Apple { static int i = 1; int b = 2; public void get() { System.out.println(i); System.out.println(b); } public void set(int b){ // 这里因为入参的名字,与字段名相同 一般使用 this 将其区分 this.b = b; } public static void main(String[] args) { Apple a = new Apple(); Apple b = new Apple(); a.get(); b.get(); /*====*/ System.out.println(" /*====*/ "); Apple.i = 10; b.set(3); a.set(4); a.get(); b.get(); } }
通过上边的输出返现 , a b 两个对象在输出 i 时是相同的,a.i b.i指向了同一个内存地址。这也说明多了无论创建多少对象,静态数据都只占一份存储区域。
静态初始化只有在必要时刻才会进行,例如,如果创建 Apple 对象 或者 不调用 Apple.i 那静态的 i 永远不会被创建出来。
多个静态初始化,可以简化成一个静态块
public class Apple { static { int i; char a; Apple c= new Apple() } }
上边这么写,因为是在大括号里,意味着是局部变量除非将对象返回出去,否则外边的方法,里边的属性
public class Apple { Apple c; static { c = new Apple(); } }
非静态实例初始化,看起来和静态块非常像,区别就是没有 static
关键字
public class Apple { Apple c; { int i; char a; c = new Apple(); } }
这个写法的非静态初始化主要是为了匿名内部类准备的。这保证了不管调用那个构造器这部分代码都会被自行
public class Apple { Apple(){ System.out.println("5"); } { System.out.println("2"); } static { System.out.println("1"); } { System.out.println("4"); } { System.out.println("3"); } public static void main(String[] args) { Apple apple = new Apple(); } }
从上边的代码运行输出可以看出,静态块先被执行,然后是非静态块,最后是,构造器