Java笔记(一)
1. 构造代码块:
1 class Person{ 2 private String name; 3 private int age; 4 5 /* 6 构造代码块 7 作用:给对象进行初始化。 8 对象一建立就运行,而且优先于构造函数执行。 9 和构造函数的区别:构造代码块是给所有对象进行统一初始化, 10 而构造函数是给对应的对象进行初始化。 11 12 构造代码块中的定义的是不同对象共性的初始化内容。 13 */ 14 { 15 System.out.println("Hello!"); 16 } 17 }
2.this关键字用于构造函数间互相调用:
1 //this语句只能定义在构造函数的第一行,因为初始化要先执行 2 class Person{ 3 private String name; 4 private int age; 5 Person(){} 6 Person(String name){ 7 this(); 8 this.name = name; 9 } 10 Person(String name, int age){ 11 this(name); //p(name); 12 this.age = age; 13 } 14 }
3. 静态:static
(1)用法:是一个修饰符,用于修饰成员(成员变量,成员函数)。
当成员被静态修饰后,就多了一个调用方式,除了可以被对象调用外还可以直接被类名调用。类名.静态成员。
(2)特点:随着类的加载而加载(即静态会随着类的消失而消失,说明它的生命周期最长);优先于对象存在;被所有对象所共享;可以直接被类名所调用。
成员变量=实例变量
静态成员变量=类变量
(3)实例变量和类变量的区别:
存放位置:类变量随着类的加载而存在于方法区(共享区)中,实例变量随着对象的建立而 存在于堆内存中;
生命周期:类变量生命周期最长,随着类的消失而消失,实例变量生命周期随着对象的消失而消失。
(4)静态的使用注意事项:
静态方法只能访问静态成员;非静态方法既可以访问静态也可以访问非静态。
静态方法中不可以定义this,super关键字,因为静态优先于对象存在。
主函数是静态的。
(5)静态有利有弊:
利:对对象的共享数据进行单独空间的存储,节省空间。没有必要对每一个对象都存储一份。可以直接被类名调用。
弊:生命周期过长。访问出现局限性(只能访问静态)。
3. 主函数:是一个特殊的函数。作为程序的入口,可以被JVM调用。
main不是关键字,是一个特殊的单词,可以被JVM识别,固定格式。
JVM在调用主函数时,传入的是new String[0]
4. 静态代码块:随着类的加载而执行,只执行一次,并优先于主函数,用于给类进行初始化。
1 class text1{ 2 static{ 3 System.out.println("b"); 4 } 5 public static void main(String[] args) { 6 new text2(); 7 new text2(); 8 System.out.println("over"); 9 } 10 static{ 11 System.out.println("c"); 12 } 13 } 14 15 class text2{ 16 static{ 17 System.out.println("a"); 18 } 19 }
执行java text1
输出
b
c
a
over
5. 对象的初始化过程:
Person p = new Person("ztq", 22);
(1)因为new用到了Person.class,所以会先找到Person.class文件并加载到内存中。
(2)执行该类中的static代码块,如果有的话,给Person.class类进行初始化。
(3)在堆内存中开辟空间,分配内存地址。
(4)在堆内存中建立对象的特有属性,并进行默认初始化。
(5)对属性进行显示初始化。
(6)对对象进行构造代码块初始化。
(7)对对象进行与之对应的构造函数初始化。
(8)将内存地址赋给栈内存中的p变量。
6. 接口:可以认为是一个特殊的抽象类,当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。用interface定义。接口是对外暴露的规则,是程序的功能扩展。
接口定义时,格式特点:
(1)接口中常见定义:常量,抽象方法。
(2)接口中的成员都有固定修饰符。常量:public static final 方法:public abstract
接口中的成员都是public
接口不可以创建对象,因为有抽象方法,需要被子类实现,子类对接口中的抽象方法全部覆盖后,子类才可以实例化,否则子类是一个抽象类。
接口可以被类多实现。这也是对多继承不支持的转换形式。
接口之间可以多继承。
7. 多态:可以理解为事物存在的多种体现形态。
多态的体现:父类的引用指向了自己的子类对象,也可以接收自己的子类对象。
多态的前提:必须是类与类之间有关系,要么继承,要么实现。存在覆盖。
多态的好处:提高程序的扩展性。
多态的弊端:提高了扩展性,但是只能使用父类的引用访问父类中的成员。
在多态(父类引用指向子类对象)中成员函数(非静态)的特点:
在编译时期:参阅引用性变量所属的类中是否有调用的方法,如果有,编译通过,没有则失败。
在运行时期:参阅对象所属的类中是否有调用的方法。
总结:成员函数在多态调用时,编译看左边,运行看右边。
在多态中成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
在多态中静态成员函数的特点:
无论编译和运行,都参考左边。
8. 内部类:将一个类定义在另一个类的里面,对里面那个类就成为内部类(内置类,嵌套类),可以被私有化。
访问特点:内部类可以直接访问外部类中的成员,包括私有成员。
而外部类要访问内部类中的成员必须要建立内部类的对象。
访问格式:
(1)当内部类定义在外部类的成员位置上,而且非私有。可以在外部其他类中,直接建立内部类对象。
外部类名.内部类名 变量名 = 外部类对象.内部类对象
Outer.Inner in = new Outer().new Inner();
(2)当内部类在成员位置上,就可以被成员修饰符所修饰。比如:private:将内部类在外部类中进行封装。static:内部类就具备了static的特性(静态内部类),只能访问外部类中的的static成员,出现了访问局限。在外部类中直接访问静态内部类的非静态成员 new Outer.Inner().function();
注意:当内部类中定义了静态成员,该内部类必须是static的。
当外部类中的静态方法访问内部类时,内部类也必须是static的。
内部类定义在局部时,不可以被成员修饰符修饰,可以直接访问外部类中的成员, 因为还持有外部类中的引用,但是不可以访问它所在的局部中的变量,只能访问被 final修饰的局部变量。 如下边代码:
1 class Outer{ 2 int x = 3; 3 void method(){ 4 final int y = 4; 5 class Inner{ 6 void function(){ 7 System.out.println(y); 8 } 9 } 10 new Inner().function(); 11 } 12 }
当描述事物时,事物的内部还有事物,该事物用内部类来描述。
匿名内部类就是内部类的简写格式。
定义匿名内部类的前提:内部类必须是继承一个类或者实现接口。
匿名内部类的格式:new 父类或者接口(){定义子类的内容}
其实匿名内部类就是一个匿名子类对象。
1 abstract class AbsDemo{ 2 abstract void show(); 3 } 4 5 class Outer{ 6 int x = 3; 7 /* 8 class Inner extends AbsDemo{ 9 void show(){ 10 System.out.println("show: " + x); 11 } 12 } 13 */ 14 public void function(){ 15 //new Inner().show(); 16 new AbsDemo(){ 17 void show(){ 18 System.out.println("show: " + x); 19 } 20 }.show(); 21 } 22 }
例:补全代码,通过匿名内部类
1 interface Inter{ 2 void method(); 3 } 4 5 class Test{ 6 //补足代码,通过匿名内部类 7 } 8 9 public class InnerClassTest{ 10 public static void main(String[] args) { 11 Test.function().method(); 12 } 13 }
由Test.function()可知Test类中有静态方法function(),但不知道返回类型。后面跟着.method(),又因为method()方法必然是非静态的,所以function()返回的是一个对象,因为只有对象才能调用method()方法。又知道只有Inter的对象才能调用method()方法,但Inter不能new对象,只有它的子类可以。因为function()方法时静态的,所以需要定义一个静态的内部类。
1 interface Inter{ 2 void method(); 3 } 4 5 class Text{ 6 7 static Inter function(){ 8 return new Inter(){ 9 public void method(){ 10 System.out.println("method run"); 11 } 12 }; 13 } 14 } 15 16 public class InnerClassTest{ 17 public static void main(String[] args) { 18 Text.function().method(); 19 } 20 }
注:当使用的方法的参数类型是接口类型时,且该接口中的方法不超过3个,这时可以定义一个匿名内部类作为参数。如:
1 public class InnerClassTest{ 2 public static void main(String[] args) { 3 4 show(new Inter(){ 5 public void method(){ 6 System.out.println("method show run"); 7 } 8 }); 9 } 10 11 public static void show(Inter in){ 12 in.method(); 13 } 14 }
9. 对捕获到的异常对象进行常见方法操作:
String getMessage():获取异常信息
String toString():异常名称,异常信息
void printStackTrace():异常名称,异常信息,异常出现的位置,其实JVM默认的异常处理机制就是在调用printStackTrace()方法,打印异常的堆栈跟踪信息
对多异常的处理:
(1)声明异常时,建议声明更为具体的异常。这样处理得可以更具体;
(2)对方声明几个异常,就对应有几个catch块,不要定义多余的,如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面;
(3)自定义异常: 自定义类必须继承Exception
原因:异常体系有一个特点,因为异常类和异常对象都被抛出。它们都具备可抛性,这 个可抛性是Throwable这个体系中独有特点,这有这个体系中的类和对象才可 以被throws和throw操作。
注:自定义异常时,如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException
1 class minusException extends Exception{ 2 private int value; 3 minusException(){} 4 minusException(String msg){ 5 super(msg); 6 } 7 minusException(String msg, int value){ 8 super(msg); 9 this.value = value; 10 } 11 public int getValue(){ 12 return value; 13 } 14 } 15 16 class Demo{ 17 public int div(int a, int b) throws minusException, ArithmeticException{ 18 if(b < 0){ 19 throw new minusException("除数出现了负数", b); 20 } 21 else if(b == 0){ 22 throw new ArithmeticException("除数出现了0"); 23 } 24 return a / b; 25 } 26 } 27 28 public class text{ 29 public static void main(String[] args) { 30 Demo d = new Demo(); 31 try{ 32 int x = d.div(4, 0); 33 System.out.println("x = " + x); 34 }catch(minusException e){ 35 System.out.println(e.toString()); 36 System.out.println("除数是:" + e.getValue()); 37 }catch(ArithmeticException e){ 38 System.out.println(e.toString()); 39 }finally{ 40 System.out.println("over"); 41 } 42 } 43 }
throws和throw的区别:
(1)throws使用在函数上,throw使用在函数内
(2)throws后面跟的是异常类,可以跟多个,用逗号隔开。throw后面跟异常对象。
注:Exception中有一个特殊的子类异常RuntimeException(运行时异常)。如果在函数内容抛出该异常,函数上可以不用声明,编译也可以通过。如果在函数上声明了该异常,调用者可以不用进行处理(即不用try或者抛)。之所以不用在函数上声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。
格式:try-catch,try-catch-finally,try-finally
异常在子父类覆盖中的体现:
(1)子类在覆盖父类时,如果父类的方法抛出异常,那么子类的覆盖方法只能抛出父类的异常或者该异常的子类。
(2)如果父类方法抛出多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。
(3)如果父类或者接口的方法中没有异常抛出,那么子类在覆盖方法时,也不可以抛出异常。如果子类方法抛出了异常,就必须要进行try处理。绝对不能抛出。
注:finally只有一种情况不会被执行。当执行到System.exit(0); finally不会执行。
例:
(1)
1 //写出程序结果 2 class Demo{ 3 public static void func(){ 4 try{ 5 throw new Exception(); 6 }finally{ 7 System.out.println("B"); 8 } 9 } 10 public static void main(String[] args) { 11 try{ 12 func(); 13 System.out.println("A"); 14 }catch(Exception e){ 15 System.out.println("C"); 16 } 17 System.out.println("D"); 18 } 19 }
编译失败。func()中抛出了一个编译时异常,并没有进行处理(没有catch,也没有在方法上声明抛出),如果方法上声明了该异常,则结果是:B C D。首先,func()方法try中抛出异常,后面的finally执行输出B,A不输出,直接跳到catch中,输出C,最后输出D。
(2)
1 //写出程序结果 2 class Test{ 3 Test(){ 4 System.out.println("Test"); 5 } 6 } 7 8 public class Demo extends Test{ 9 Demo(){ 10 super(); 11 System.out.println("Demo"); 12 } 13 public static void main(String[] args) { 14 new Demo(); 15 new Test(); 16 } 17 }
输出结果:Test Demo Test
(3)
1 //写出程序结果 2 interface A{} 3 4 class B implements A{ 5 public String func(){ 6 return "func"; 7 } 8 } 9 10 public class Demo{ 11 public static void main(String[] args) { 12 A a = new B(); 13 System.out.println(a.func()); 14 } 15 }
编译失败。接口A中并没有func()方法。
(4)
1 //写出程序结果 2 class Fu{ 3 boolean show(char a){ 4 System.out.println(a); 5 return true; 6 } 7 } 8 9 class Demo extends Fu{ 10 public static void main(String[] args) { 11 int i = 0; 12 Fu f = new Demo(); 13 Demo d = new Demo(); 14 for(f.show('A'); f.show('B') && (i < 2); f.show('C')){ 15 i++; 16 d.show('D'); 17 } 18 } 19 boolean show(char a){ 20 System.out.println(a); 21 return false; 22 } 23 }
输出结果:A B
(5)
1 //写出程序结果 2 interface A{} 3 4 class B implements A{ 5 public String test(){ 6 return "yes"; 7 } 8 } 9 10 public class Demo{ 11 static A get(){ 12 return new B(); 13 } 14 public static void main(String[] args) { 15 A a = get(); 16 System.out.println(a.test()); 17 } 18 }
编译失败。接口A中没有test()方法。
(6)
1 //写出程序结果 2 class Super{ 3 int i = 0; 4 public Super(String a){ 5 System.out.println("A"); 6 } 7 public Super(){ 8 System.out.println("B"); 9 i += 2; 10 } 11 } 12 13 public class Demo extends Super{ 14 public Demo(String a){ 15 System.out.println("C"); 16 i = 5; 17 } 18 public static void main(String[] args) { 19 int i = 4; 20 Super d = new Demo("A"); 21 System.out.println(d.i); 22 } 23 }
输出结果:B C 5。先执行super(),即Super(),输出B,i变为2。接着执行Demo的构造方法,输出C,i变为5。
(7)
1 interface Inter{ 2 void show(int a, int b); 3 void func(); 4 } 5 6 public class Demo{ 7 public static void main(String[] args) { 8 //补足代码:调用两个函数,要求用匿名内部类 9 Inter in = new Inter(){ 10 public void show(int a, int b){ 11 12 } 13 14 public void func(){ 15 16 } 17 }; 18 in.show(1, 2); 19 in.func(); 20 } 21 }
(8)
1 //写出程序结果 2 class TD{ 3 int y = 6; 4 class Inner{ 5 static int y = 3; 6 void show(){ 7 System.out.println(y); 8 } 9 } 10 } 11 12 class TC{ 13 public static void main(String[] args) { 14 TD.Inner ti = new TD().new Inner(); 15 ti.show(); 16 } 17 }
编译失败:TD类中的内部类Inner中有一个静态成员y,而Inner类却不是静态类。
(9)
选择题,写出错误答案错误的原因,用单行注释的方式。
1 class Demo{ 2 int show(int a, int b){ 3 return 0; 4 } 5 }
A.public int show(int a, int b){return 0;} //可以,覆盖。 B.private int show(int a, int b){return 0;} //不可以,权限不够。 C.private int show(int a, long b){return 0;} //可以,和父类不是一个函数。没有覆盖,相当于重载。 D.public short show(int a, int b){return 0;} //不可以,该函数不可以和给定函数出现在同一类或子父类中。 E.static int show(int a, int b){return 0;} //不可以,静态只能覆盖静态。
(10)
1 //写出程序结果 2 class Fu{ 3 int num = 4; 4 void show(){ 5 System.out.println("showFu"); 6 } 7 } 8 9 class Zi extends Fu{ 10 int num = 5; 11 void show(){ 12 System.out.println("showZi"); 13 } 14 } 15 16 public class Demo{ 17 public static void main(String[] args) { 18 Fu f = new Zi(); 19 Zi z = new Zi(); 20 System.out.println(f.num); 21 System.out.println(z.num); 22 f.show(); 23 z.show(); 24 } 25 }
输出结果:4 5 showZi showZi
(11)
1 interface A{ 2 void show(); 3 } 4 5 interface B{ 6 void add(int a, int b); 7 } 8 9 class C implements A, B{ 10 //补全程序代码 11 private int sum = 0; 12 public void show(){ 13 System.out.println(sum); 14 } 15 16 public void add(int a, int b){ 17 sum = a + b; 18 } 19 } 20 21 public class Demo{ 22 public static void main(String[] args) { 23 C c = new C(); 24 c.add(4, 2); 25 c.show(); //通过该函数打印以上两个数的和 26 } 27 }
(12)
1 //写出程序结果 2 public class Demo{ 3 public static void main(String[] args) { 4 try{ 5 showExce(); 6 System.out.println("A"); 7 }catch(Exception e){ 8 System.out.println("B"); 9 }finally{ 10 System.out.println("C"); 11 } 12 System.out.println("D"); 13 } 14 public static void showExce() throws Exception{ 15 throw new Exception(); 16 } 17 }
输出结果:B C D
(13)
1 //写出程序结果 2 class Super{ 3 int i = 0; 4 Super(){} 5 public Super(String s){ 6 i = 1; 7 } 8 } 9 10 class Demo extends Super{ 11 public Demo(String s){ 12 i = 2; 13 } 14 public static void main(String[] args) { 15 Demo d = new Demo("yes"); 16 System.out.println(d.i); 17 } 18 }
输出结果:2
(14)
1 //写出程序结果 2 class Super{ 3 public int get(){ 4 return 4; 5 } 6 } 7 8 class Demo extends Super{ 9 public long get(){ 10 return 5; 11 } 12 public static void main(String[] args) { 13 Super s = new Demo(); 14 System.out.println(s.get()); 15 } 16 }
编译失败。因为子父类中的get()方法没有被覆盖,子类调用时候不能明确返回的值是什么类型,所以这样的函数不能存在于子父类中。
(15)
1 //写出程序结果 2 public class Demo{ 3 public static void func() { 4 try{ 5 throw new Exception(); 6 System.out.println("A"); 7 }catch(Exception e){ 8 System.out.println("B"); 9 } 10 } 11 public static void main(String[] args) { 12 try{ 13 func(); 14 }catch(Exception e){ 15 System.out.println("C"); 16 } 17 System.out.println("D"); 18 } 19 }
编译失败。因为打印A的输出语句一定执行不到,throw单独存在时,后面不要写语句。就像return,break一样。
(16)
1 public class Demo{ 2 public void func(){ 3 //位置1 4 } 5 class Inner{} 6 public static void main(String[] args) { 7 Demo d = new Demo(); 8 //位置2 9 } 10 }
A.在位置1写 new Inner(); √ 外部类访问内部类。 B.在位置2写 new Inner(); × main函数是静态的,不能访问非静态类。 C.在位置2写 new d.Inner(); × 格式错误。把d还原为new Demo(),即new new Demo().Inner(); D.在位置2写 new Demo.Inner(); × 因为Inner不是静态的。
(17)
1 //写出程序结果 2 class Exc0 extends Exception{} 3 class Exc1 extends Exc0{} 4 5 public class Demo{ 6 public static void main(String[] args) { 7 try{ 8 throw new Exc1(); 9 }catch(Exception e){ 10 System.out.println("Exception"); 11 }catch(Exc0 e){ 12 System.out.println("Exc0"); 13 } 14 } 15 }
编译失败。多个catch时,父类的catch要放在下面。
(18)
1 interface Test{ 2 void func(); 3 } 4 5 public class Demo{ 6 public static void main(String[] args) { 7 //补足代码:(匿名内部类) 8 new Demo().show(new Test(){ 9 public void func(){} 10 }); 11 12 } 13 void show(Test t){ 14 t.func(); 15 } 16 }
(19)
1 //写出程序结果 2 public class Demo{ 3 public static String output = ""; 4 public static void foo(int i){ 5 try{ 6 if(i == 1){ 7 throw new Exception(); 8 } 9 output += "1"; 10 }catch(Exception e){ 11 output += "2"; 12 return; 13 }finally{ 14 output += "3"; 15 } 16 output += "4"; 17 } 18 public static void main(String[] args) { 19 foo(0); 20 System.out.println(output); 21 foo(1); 22 System.out.println(output); 23 } 24 }
输出结果:134 13423
(20)
1 //补足compare函数内的代码,不许添加其他函数 2 class Circle{ 3 private static double PI = 3.14; 4 private double radius; 5 public Circle(double r){ 6 radius = r; 7 } 8 public static double compare(Circle[] cir){ 9 //程序代码,就是在求数组中的最大值 10 double maxR = cir[0].radius; 11 for(int i = 1; i < cir.length; i++){ 12 if(cir[i].radius > maxR){ 13 maxR = cir[i].radius; 14 } 15 } 16 return maxR; 17 } 18 } 19 20 public class Demo{ 21 public static void main(String[] args) { 22 Circle cir[] = new Circle[3]; //创建了一个类类型数组 23 cir[0] = new Circle(1.0); 24 cir[1] = new Circle(2.0); 25 cir[2] = new Circle(4.0); 26 System.out.println("最大的半径值是:" + Circle.compare(cir)); 27 } 28 }
(21)
1 //写出程序结果 2 public class Demo{ 3 private static int j = 0; 4 private static boolean methodB(int k){ 5 j += k; 6 return true; 7 } 8 public static void methodA(int i){ 9 boolean b; 10 b = i < 10 | methodB(4); 11 b = i < 10 || methodB(8); 12 } 13 public static void main(String[] args) { 14 methodA(0); 15 System.out.println(j); 16 } 17 }
输出结果:4。 因为|和&需要检查每一个条件的真伪。