第五章
1.构造器是什么?
构造函数(构造器)是一种特殊的函数。其主要功能是用来在创建对象时初始化对象, 即为对象成员变量赋初始值,总与new运算符一起使用在创建对象的语句中。构造函数与类名相同,没有返回值,但不能声明void,访问权限可以为任意,但是一般情况下使用public方法权限,构造方法中的参数可以根据需要自行定义,可重载多个不同的构造函数。在JAVA语言中,构造函数与C++语言中的构造函数相同,JAVA语言中普遍称之为构造方法。
2.重载和重写有什么区别?
重载(overloading):在同一个类中同名函数,具有不同参数个数和类型(返回值不参与),是一个类中多态性的体现。是由静态类型确定,在类加载的时候就已经确定了,属于静态绑定。(当子类和父类存在同一个方法时,子类重写父类方法时,程序在运行时调用的方法时,是调用父类(接口)的方法呢?还是调用子类的方法呢?我们将确定这种调用何种方法的操作称之为绑定。)
重写(overriding):子类中含有与父类中相同的名字、返回值类型和参数表的方法,则是重写。是在继承中体现多态性,属于动态绑定。
方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态,后者实现的是运行时的多态。
3.this 和super关键字
this:
this 是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。
this 的用法在 Java 中大体可以分为3种:
1.普通的直接引用
这种就不用讲了,this 相当于是指向当前对象本身。
2.形参与成员名字重名,用 this 来区分:
class Person {
private int age = 10;
public Person(){
System.out.println("初始化年龄:"+age);
}
public int GetAge(int age){
this.age = age;
return this.age;
}
}
public class test1 {
public static void main(String[] args) {
Person Harry = new Person();
System.out.println("Harry's age is "+Harry.GetAge(12));
}
}
可以看到,这里 age 是 GetAge 成员方法的形参,this.age 是 Person 类的成员变量。
super
super 可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。
super 也有三种用法:
1.普通的直接引用
与 this 类似,super 相当于是指向当前对象的父类,这样就可以用 super.xxx 来引用父类的成员。
2.子类中的成员变量或方法与父类中的成员变量或方法同名
class Country {
String name;
void value() {
name = "China";
}
}
class City extends Country {
String name;
void value() {
name = "Shanghai";
super.value(); //调用父类的方法
System.out.println(name);
System.out.println(super.name);
}
public static void main(String[] args) {
City c=new City();
c.value();
}
}
可以看到,这里既调用了父类的方法,也调用了父类的变量。若不调用父类方法 value(),只调用父类变量 name 的话,则父类 name 值为默认值 null。
3.引用构造函数
- super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。
- this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。
class Person {
public static void prt(String s) {
System.out.println(s);
}
Person() {
prt("父类·无参数构造方法: "+"A Person.");
}//构造方法(1)
Person(String name) {
prt("父类·含一个参数的构造方法: "+"A person's name is " + name);
}//构造方法(2)
}
public class Chinese extends Person {
Chinese() {
super(); // 调用父类构造方法(1)
prt("子类·调用父类"无参数构造方法": "+"A chinese coder.");
}
Chinese(String name) {
super(name);// 调用父类具有相同形参的构造方法(2)
prt("子类·调用父类"含一个参数的构造方法": "+"his name is " + name);
}
Chinese(String name, int age) {
this(name);// 调用具有相同形参的构造方法(3)
prt("子类:调用子类具有相同形参的构造方法:his age is " + age);
}
public static void main(String[] args) {
Chinese cn = new Chinese();
cn = new Chinese("codersai");
cn = new Chinese("codersai", 18);
}
}
从本例可以看到,可以用 super 和 this 分别调用父类的构造方法和本类中其他形式的构造方法。
例子中 Chinese 类第三种构造方法调用的是本类中第二种构造方法,而第二种构造方法是调用父类的,因此也要先调用父类的构造方法,再调用本类中第二种,最后是重写第三种构造方法。
从本质上讲,this 是一个指向本对象的指针, 然而 super 是一个 Java 关键字。
4.初始化顺序
正常类的加载顺序:静态变量/静态代码块 -> main方法 -> 非静态变量/代码块 -> 构造方法
如果是继承关系的子类初始化顺序:
父类–静态变量/父类–静态初始化块
子类–静态变量/子类–静态初始化块
父类–变量/父类–初始化块
父类–构造器
子类–变量/子类–初始化块
子类–构造器
第六章
1.JAVA中的权限关键字
第七章
1.组合和继承的区别,如何选择使用?
组合:其实一开始就接触了但不知道这就叫组合,本质就是类的复用。我们创建一个类A,之后再创建一个新的类B,在B类中通过创建A类对象,来调用A类方法。
下面通过具体的例子来展示如何使用:
public class People {
private String name;
private int age;
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
public void setAge(int age){
this.age = age;
}
}
class Student {
People people = new People();
}
这里的Student类就是运用了组合。
继承:这个很熟悉了,直接贴用法
public class Student extends People{
//doSomething
}
总结一下:
组合:只需在新的类中产生现有类的对象。新的类是由现有类的对象所组成的。
继承:按照现有类的类型来创建新类,无需改变现有类的形式,并且在其中添加新的代码。
区别:组合是显示地允许在新类中放置子对象,而继承是隐性的这样做。
选择使用问题:
从语言的逻辑上看,继承(extend)更应该用于包含关系(sth is a sth_baby),而组合可以是并列或者说共有的关系(sth has a sth_baby)。
2.final关键字总结
final关键字可以修饰变量、方法和类。
1.用来修饰数据:包括成员变量和局部变量,该变量只能被赋值一次且它的值无法被改变。对于成员变量来讲,修饰的类变量,必须在声明时初始化;修饰的实例变量,必须在声明时或者构造方法中对它赋值。对于基本数据类型,final会使得数值不变;而对于引用类型,final会使得引用指向的对象不变。
2.用来修饰方法:第一个原因表示该方法无法被重写,防止继承的子类去修改该方法;第二个原因是效率。
tips:类中所有private方法都隐式地使用了final关键字。
3修饰类:表示该类无法被继承
第八章
1.为什么要有多态的存在?
个人简单的理解:父类型的引用指向子类型的对象。使用多态有两个好处:
1. 应用程序不必为每一个派生类编写功能调用,只需要对抽象基类进行处理即可。大大提高程序的可复用性。
2. 派生类的功能可以被基类的方法或引用变量所调用,这叫向后兼容,可以提高可扩充性和可维护性。
多态可以用在方法的参数中和方法的返回类型中。
举个例子:
package stduy;
abstract class Animal{
abstract void eat();
}
class Dog extends Animal{
public void eat() {
System.out.println("啃骨头!");
}
public void LookHome() {
System.out.println("看家!");
}
}
class Cat extends Animal{
public void eat() {
System.out.println("吃鱼!");
}
public void catchMouse() {
System.out.println("抓老鼠!");
}
}
public class Main{
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
dog.LookHome();
Cat cat = new Cat();
cat.eat();
cat.catchMouse();
}
}
这里主方法分别去调用各个子类的eat方法就很麻烦,我们这里就可以使用多态。
public class Main{
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
method(dog);
method(cat);
}
public static void method(Animal a) {
a.eat();
}
}
2.向上转型和向下转型是什么,为什么要用它们?
向上转型和向下转型都非常抽象,需要举例说明:
class Father {
String name = "爸爸";
public void sleep() {//睡觉方法
System.out.println(name + "睡觉");
}
}
/**
* 子类继承父类
*/
class Son extends Father {
String name = "儿子";
public void p() {//调皮方法
System.out.println(name + "调皮");
}
我们先建立一堆父子类。
public class UpAndDown {
public static void main(String[] args) {
// 向上转型:将父类引用指向子类对象
Father f = new Son();
f.sleep();//输出“爸爸睡觉”
//如果f.p();编译出错,不可执行。因为p()不是Father的方法。
}
}
很明显,上面的就是向上转型,将子类转型成父类,此时子类特有的p()方法就无法调用,但这样做,方便我统一控制多个子类。
public class UpAndDown {
public static void main(String[] args) {
// 向下转型
Father f = new Son();
((Son)f).P();//输出“儿子调皮”
}
}
上面就是向下转型,将向上转型的子类再向下转型,这样原本子类特有的方法p()就可以使用了。
public class UpAndDown {
public static void main(String[] args) {
// 直接向下转型
Father f = new Father();
f.sleep();//输出“爸爸睡觉”
((Son)f).P();//报错!!!!!!!!!!
}
}
但如果我写成以上的向下转型就不行,因为他在创建对象时创建的就是父类对象,根本就不包含子类特有的方法,无法下转。所以下转的前提是你本来就有,只不过由于向上转型失去了,然后通过下转再次恢复。
为什么要用它们
向上转型:这个好理解java的继承,多态. 利于程序扩展。这种设计方式,会让你写出更易维护,简洁的代码。
但向下转型就有点难以理解了,为什么我要先上转再下转,多这一步呢,我子类引用指向新建的一个子类对象不就好了?
这篇博客写的很详细: