1、构造方法(构造器)
(1)作用:用于对对象的数据进行初始化
(2)格式: A:方法名和类名相同;没有返回值类型,连void都不能有;没有返回值
修饰符 类名(){
代码块;
}
(3)注意事项:
A:如果我们没写构造方法,系统将提供一个默认的无参构造方法
B:如果我们给出了构造方法,系统将不再提供默认构造方法
2、代码块
(1)概述:用{}括起来的代码。
(2)分类:A:局部代码块:用于限定变量的生命周期,及早释放,提高内存利用率。
B:构造代码块。把多个构造方法中相同的代码可以放到这里,每个构造方法执行前,首先执行构造代码块。
C:静态代码块。对类的数据进行初始化,仅仅只执行一次。
顺序:静态代码块 > 构造代码块 > 局部代码块
3、封装
(1)隐藏实现细节,提供公共的访问方式
(2)好处:
A:隐藏实现细节,提供公共的访问方式
B:提高代码的复用性
C:提高代码的安全性
(3)设计原则:把不想让外界知道的实现细节给隐藏起来,提供公共的访问方式
(4)private是封装的一种体现。封装:类,方法,private修饰成员变量
4、继承(extends)
(1)概述:如果多个类存在相同的属性和行为,可以单独抽出来相同的做一个类。就不要重复。
(2)格式:class 子类名 extends 父类名
(3)好处:提高了代码的复用性;提高了代码的维护性;让类与类之间产生了关系,是多态的前提。
(4)弊端:A:让类的耦合性增强。这样某个类的改变,就会影响其他和该类相关的类。
原则:低耦合,高内聚。
耦合:类与类的关系
内聚:自己完成某件事情的能力
B:打破了封装性
(5)特点:Java只支持单继承,不支持多继承;Java支持多层继承(继承体系)
(6)注意事项
A.子类只能继承父类所有非私有的成员(成员方法和成员变量)
B.子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法
C.不要为了部分功能而去继承
(7)继承中的成员关系
A.成员变量
a.子类的成员变量名称和父类中的成员变量名称不一样(这个没问题)
b.子类的成员变量名称和父类中的成员变量名称一样。查找顺序:子类方法中的局部变量—>子类的成员变量—>父类的成员变量—>找不到
B.构造方法
a.子类的构造方法默认会去访问父类的无参构造方法
b.父类中如果没有无参构造方法,子类通过super去明确调用带参构造
C:成员方法
a:子类的成员方法和父类中的成员方法名称不一样(这个没问题)
b:子类的成员方法和父类中的成员方法名称一样。查找顺序:子类—>父类—>找不到
(8)super和this
见名知意,super一般是与父类的成员变量和方法有关,this一般是和子类本身的成员变量和方法有关。
格式:访问成员变量:this.成员变量 super.成员变量
访问构造方法:this(…) super(…)
访问成员方法:this.成员方法() super.成员方法()
(9)继承中构造方法的规则
A.子类构造方法一定会调用父类的构造方法
B.如果父类有无参构造方法,子类可以不写会默认调用无参构造方法,即隐式调用。
C.如果父类没有无参构造,只有有参构造,子类必须自己调用父类构造方法,即显式调用。
D.子类也可以用this调用本类的其他构造方法。
E.使用super关键字、this关键词时,必须写在构造方法的第一行。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*(1)运行下面代码的结果是什么?
public class A {
public int a = 0;
public A(int a) {
this.a = a;
}
}
public class B extends A{
public int a = 1;
public B() {
a = 2;
}
}
public class Test {
public static void main(String[] args) {
B b = new B();
System.out.println(b.a);
}
}
编译不通过,父类既然有了有参构造,那就没有无参构造方法了。子类不能默认调用无参构造方法了,所以必须显式调用父类的构造方法了。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
5、方法重载和方法重写(前面不想讲重载,放在这里讲,方便对比)
(1)重载(overload)
A.概述:对于类的方法来说,如果有两个方法的方法名相同,但是参数不同,就可以说是重载。
B.条件:方法名相同;
方法的参数类型个数、顺序至少有一项不同;
方法的返回类型没有限制,可以不同;
方法的修饰符没有限制,可以不同。
C.举例:public void fun1(int a,double b){ }
public void fun1(int a,int b){ }
(2)重写(override)
A.概述:子类继承父类,子类出现和父类相同的方法,方法体不同,就成为重写。
B.条件:子类继承父类;
子类和父类的方法相同(参数完全相同,返回值相同);
子类方法的访问权限必须大于等于父类方法的访问权限;
父类的静态方法不能被重写为非静态方法;
父类的非静态方法不能被重写为静态方法;
父类的抽象方法可以被非抽象子类实现或者抽象子类重新声明为抽象方法;
父类的非抽象方法可以被重写为抽象方法。
C.举例:(父类)public int fun1(int a,int b){ return a+b; }
(子类)private int fun1(int a,int b){ return a-b; }
(3)重写和重载的异同
A.相同点:都要相同的方法名;
都可以用于抽象方法和非抽象方法之间。
B.不同点:重写要求参数类型一致,而重载要求参数类型不一致;
重写要求返回类型一致,而重载不作限制;
重写只能用于子类重写父类方法,而重载用于同一类下的所有方法;
重写对于方法的访问权限和抛出异常有特殊要求,而重载没有任何限制。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*(1)下面已经定义一个类,选项中哪些方法加进去能确保编译正确?
public class Test {
public void fun(int a, int b, double c) {}
}
A.public void fun(int a, double b, int c) {}
B.public void fun(int a, int b, int c) {}
C.public int fun(int a, int b, double c) {}
D.abstract void fun();
E.public void Fun(int a, int c, double b)
选A,B,E A可以,顺序不同;B可以,参数类型不同;C不可以,参数不同,返回类型不同,并不是重载,只会是包编译错误;D不可以,如果抽象方法必须在抽象类中;E正确,方法名不同,区分大小。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
6、多态
(1)概述:同一个对象在不同时刻体现出来的不同状态。
(2)前提:有继承或者实现关系;有方法重写;有父类或者父接口引用指向子类对象。
(3)分类:
A.实体类多态:class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
B.抽象类多态:abstract class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
C:接口多态:interface Fu {}
class Zi implements Fu {}
Fu f = new Zi();
(4)多态的成员访问特点:
A.成员变量:编译看左边,运行看左边。
B.构造方法:子类的构造都会默认访问父类无参构造,对父类的数据进行初始化。
C.成员方法:编译看左边,运行看右边。
D.静态方法:编译看左边,运行看右边。
(5)多态的好处:A:提高代码的维护性(继承体现)
B:提高代码的扩展性(多态体现)
(6)多态的弊端:父类不能使用子类的特有功能。(但是可以强转)
(7)多态的转型:A:向上转型 从子到父
B:向下转型 从父到子
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*(1)下面代码执行后的结果是什么?
public class Fu {
{
System.out.println("父构造块");
}
static{
System.out.println("父静态块");
}
public Fu() {
System.out.println("父构造函数");
}
}
public class Zi extends Fu{
{
System.out.println("子构造块");
}
static{
System.out.println("子静态块");
}
public Zi() {
System.out.println("子构造函数");
}
}
public class Test {
public static void main(String[] args) {
Fu a = new Zi();
}
}
结果:父类静态块,子类静态块,父类构造块,父类构造函数,子类构造块,子类构造函数。分析:静态块、静态变量随着类的加载而初始化,且这只加载一次。其次创建对象时,父类成员变量初始化优先于子类,构造块优先于构造方法。父类对象先执行构造块再执行构造方法。最后执行子类的构造块再执行构造方法。
*(2)下面代码执行后的结果是什么?
public class Fu {
public int var_a = 1;
static int var_b = 1;
private int var_c = 1;
public int getC() {
return var_c;
}
}
public class Zi extends Fu{
public int var_a = 2;
static int var_b = 2;
private int var_c = 2;
private static int a = 2;
public int getC() {
return var_c;
}
}
public class Test {
public static void main(String[] args) {
Fu sb = new Zi();
System.out.println(sb.var_a);
System.out.println(sb.var_b);
System.out.println(sb.getC());
}
}
结果:1 1 2。 分析:编译看左边,运行看右边。成员变量、静态变量的取值主要是看左边的类名是父类还是子类,取值就去相对应的类去取。但是方法的调用是看右边的,如果子类中存在,就调用子类的,子类中不存在就调用父类的。补充:静态方法不存在重写这一个说法。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------