OOP
继承
继承的内容
- 子类继承到父类的哪些东西?
所有
- 子类以及子类对象可以调用到继承的哪些属性和方法?
要看 父类的属性、方法的具体访问修饰符:
访问修饰符 | 访问范围 |
---|---|
public | 项目里 |
private | 类里 |
protected | 包下,不同包的子类 |
缺省 | 同包下 |
那么对于子类来说,
同包下:
只有private不能调用
不同包下:
public,protected 可以调用
protected 受保护的,子类不能访问父类的私有字段。不过有时候希望限制父类中的某个方法只允许子类访问,或者希望子类的方法访问超类的某个字段。
方法重写:
注解格式:除方法体之外与父类一致
访问修饰符:
子类中重写的方法,与父类权限一致或者大于(因为子类继承,希望它有更强的扩展性,所以权限理应更大)
返回值类型:
与父类方法的返回值类型类/子类
参数:
参数类型 不能修改
对于子类而言:子类及子类对象可以优先调用重写之后的
重载:
方法名相同,参数不一致(子类 父类也可以实现重载,并不会归为一种类型)
自动转型:
强制转型:int i = (int)1.2;
A a = new B();
A 是 B 的 父类——> 祖先
向上转型 之后 还会优先调用重写的方法吗?
会
子类对像 向上 -> 父类类型 ——>向下转回子类类型 【可以】
父类对象 --> 向下转型 子类类型 (对象 无中生有 子类可能有一些特别的属性方法 父类没有)【不可以】
注意:子类向上转型后,只能调用父类有的方法,并且是调的子类覆盖重写的,而不能调用子类独立的方法;子类独有的方法在父类中根本没有定义,所以父类无法找到子类独有的方法。
任务:一个类实例化的加载过程:
顺序:
1.加载静态成员/代码块:
先递归地加载父类的静态成员/代码块(Object的最先);再依次加载到本类的静态成员。
同一个类里的静态成员/代码块,按写代码的顺序加载。
如果其间调用静态方法,则调用时会先运行静态方法,再继续加载。同一个类里调用静态方法时,可以不理会写代码的顺序。
调用父类的静态成员,可以像调用自己的一样;但调用其子类的静态成员,必须使用“子类名.成员名”来调用。
2.加载非静态成员/普通代码块,初始化构造方法:(实例块在创建对象时才会被加载。而静态成员在不创建对象时可以加载)
先递归地加载父类的非静态成员/代码块(Object的最先),非静态成员和代码块按代码出现顺序加载,并在加载完非静态成员后初始化构造方法;再依次加载到本类的非静态成员,并初始化构造方法,默认为无参构造,当然也可以指定父类初始化构造方法,和本类初始化构造方法。在子类构造方法中用super(参数列表);可以指定初始化父类构造方法,默认不写super(参数列表)为初始化父类无参构造方法。
同一个类里的非静态成员/普通代码块,按写代码的顺序加载。同一个类里调用方法时,可以不理会写代码的顺序。
但调用属性时,必须注意加载顺序。一般编译就会不通过。
调用父类的非静态成员(private 除外),也可以像调用自己的一样。
问题:静态代码块只加载一次,静态方法先于静态代码块?
这里要看情况,我这里样例是 由于声明成员变量时调用到了静态方法 所以静态方法优先于静态代码块 但实际上这两者本没有优先区别
class Base{
public static int a = 10;
public int b = 20;
static
{
System.out.println("Static Init Base " + a);
//System.out.println("Null Init " + b);
}
public Base()
{
System.out.println("Init Base " + this.b);
}
}
/**
*一级子类和基类包含的内容一样
**/
class SuperClass extends Base{
//静态变量、静态块执行顺序,按书写先后顺序
public static int a1 = getSuperStaticNumber();
public int b1 = getSuperInstanceNumber();
public SuperClass()
{
System.out.println("Init SuperClass" + this.b1);
}
static
{
System.out.println("Static Init SuperClass" + a1);
}
public static int getSuperStaticNumber()
{
System.out.println("Static member init");
return 100;
}
public int getSuperInstanceNumber()
{
System.out.println("Instance member init");
return 200;
}
}
/**
*二级子类为测试该代码的驱动类
*/
public class Sub extends SuperClass{
public static int a2 = getStaticNumber();
public int b2 = getInstanceNumber();
public Sub()
{
System.out.println("Init SubClass " + this.b2);
}
public static int getStaticNumber()
{
System.out.println("Static member init Sub");
return 1000;
}
public int getInstanceNumber()
{
System.out.println("Instance member init Sub");
return 2000;
}
static
{
System.out.println("Static Init " + a2);
}
/**
* 程序入口,main
*
* */
public static void main(String args[])
{
new Sub();
}
}
输出结果:
几个面试常见问题:
- 请解释hashCode()和equals()方法有什么联系?
Java对象的eqauls方法和hashCode方法是这样规定的:
➀相等(相同)的对象必须具有相等的哈希码(或者散列码)。
➁如果两个对象的hashCode相同,它们并不一定相同。
- 若对一个类不重写,它的equals()方法是如何比较的?
地址
- 请说明Java中的方法覆盖(Overriding)和方法重载(Overloading)是什么意思?
Java中的方法重载发生在同一个类里面两个或者是多个方法的方法名相同但是参数不同的情况。
与此相对,方法覆盖是说子类重新定义了父类的方法。
方法覆盖必须有相同的方法名,参数列表和返回类型。覆盖者可能不会限制它所覆盖的方法的访问。
- 请判断,两个对象值相同(x.equals(y) == true),但却可有不同的hash code,该说法是否正确,为什么?
不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。
Java对于eqauls方法和hashCode方法是这样规定的:
(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同;
(2)如果两个对象的hashCode相同,它们并不一定相同。
当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降
(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)
- 请判断当一个对象被当作参数传递给一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
是值传递。Java 编程语言只有值传递参数。
当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的引用。
对象的内容可以在被调用的方法中改变,但对象的引用是永远不会改变的。
Java是值传递 就算传的是对象 也是传的对象地址
https://www.zhihu.com/question/31203609/answer/164430457
接口
由于Java不支持多继承,而有可能某个类或对象要使用分别在几个类或对象里面的方法或属性,现有的单继承机制就不能满足要求。
与继承相比,接口有更高的灵活性,因为接口中没有任何实现代码。当一个类实现了接口以后,该类要实现接口里面所有的方法和属性,并且接口里面的属性在默认状态下面都是public static,所有方法默认情况下是public.一个类可以实现多个接口。