javaSE(四)

版权声明:博主原创,转发请私信。 https://blog.csdn.net/YooFale/article/details/82801457

1.代码块

局部代码块:在方法中出现,及早释放变量,限定了变量的生命周期

构造代码块:在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行,每创建一次对象,就执行一次

静态代码块:在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。(一般用来加载驱动

静态代码块优先于主方法,构造代码块优先于构造方法,再次创建只会重复执行构造代码块和构造方法。

测试代码如下:

public class Practice {
	static {
		System.out.println("主方法前面的静态代码块");
	}

	public static void main(String[] args) {
		System.out.println("我是main方法");

		Student s1 = new Student();
		Student s2 = new Student();
	}

}

class Student {
	static {
		System.out.println("Student 静态代码块");
	}

	{
		System.out.println("Student 构造代码块");
	}

	public Student() {
		System.out.println("Student 构造方法");
	}
}

2.继承extends

可以让两个类产生父子关系

提高了代码的复用性和维护性,是多态的前提

弊端是类之间的耦合增加了

此处开发的原则:高内聚,低耦合

内聚:自己完成某件事的能力

耦合:两个类之间的关系

继承的特点:只支持多层继承,不支持多继承

实际使用中:

①想用体系中所有的功能,就要用最底层(孙子辈)的类创建对象。

②想看这个体系的共有功能,就看最顶层。(爷爷辈)

继承的注意事项:

子类只能继承父类的非私有成员(成员变量,成员方法)

子类不能继承父类的构造方法,但是可以通过super去访问父类的构造方法

使用继承的情况:

碰到类关系是谁是谁的一种的时候,可以使用继承

子类和父类当有同名变量的时候,就近原则,使用子类的值。(就近原则)(实际开发中,并不会出现)

3.this和super

this代表当前对象的引用

super代表当前对象父类的引用

代码案例:

class Father {
	int num1 = 10;
	int num2 = 30;
}

class Son extends Father {
	int num2 = 20;

	public void print() {
		System.out.println(this.num1);				//this既可以调用本类的,也可以调用父类的(本类没有的情况下)
		System.out.println(this.num2);				//就近原则,子类有就不用父类的了
		System.out.println(super.num2);
	}

第二句输出为20,第三句是30

4.子类和父类构造方法

子类的所有构造方法默认会访问父类的无参构造方法。(相当于子类的所有构造方法,第一句都是super())

原因?

子类继承父类的数据,甚至可能使用父类的数据。所以在子类数据初始化之前,必须先完成对父类数据的初始化。

super() object是没有明显父类的类的父类,即顶级父类。

父类没有空参构造方法怎么办?

super解决方法:

子类无参构造内写法:super("张三",23),有参构造内写法:super(name,age)(子类无参和子类有参都直接调用父类有参构造方法

this解决方法:

子类中无参构造内写法:this("张三",23),有参构造内写法:super(name,age)(子类无参调用子类有参,子类有参调用父类有参

class Father {
	private String name;			//姓名
	private int age;				//年龄

	public Father() {				//空参构造
		System.out.println("Father 空参构造");
	}

	public Father(String name,int age) {	//有参构造
		this.name = name;
		this.age = age;
		System.out.println("Father 有参构造");
	}

	public void setName(String name) {	//设置姓名
		this.name = name;
	}

	public String getName() {			//获取姓名
		return name;
	}

	public void setAge(int age) {		//设置年龄
		this.age = age;
	}

	public int getAge() {				//获取年龄
		return age;
	}
}

class Son extends Father {
	public Son() {						//空参构造
		this("王五",25);				//本类中的构造方法
		//super("李四",24);				//调用父类中的构造方法
		
		System.out.println("Son 空参构造");
	}

	public Son(String name,int age) {	//有参构造
		super(name,age);
		System.out.println("Son 有参构造");
	}
}

5.继承面试题

第一则:

class Fu{
	public int num = 10;
	public Fu(){
		System.out.println("fu");
	}
}
class Zi extends Fu{
	public int num = 20;
	public Zi(){
		//super();
		System.out.println("zi");
	}
	public void show(){
		int num = 30;
		System.out.println(num);
		System.out.println(this.num);
		System.out.println(super.num);
	}
}
class Test1_Extends {
	public static void main(String[] args) {
		Zi z = new Zi();
		z.show();
	}
}

在本类中,利用无参构造新建对象,zi类无参构造先调用fu类无参构造,所以先输出fu,再输出zi

show方法中,第一个num为30,this是本类(zi类),向上看是20,super是fu类,再往上看,是10.

第二则:

class Test2_Extends {
	public static void main(String[] args) {
		Zi z = new Zi();
	}
	/*
	1,jvm调用了main方法,main进栈
	2,遇到Zi z = new Zi();会先将Fu.class和Zi.class分别加载进内存,再创建对象,当Fu.class加载进内存
	父类的静态代码块会随着Fu.class一起加载,当Zi.class加载进内存,子类的静态代码块会随着Zi.class一起加载
	第一个输出,静态代码块Fu,第二个输出静态代码块Zi
	3,走Zi类的构造方法,因为java中是分层初始化的,先初始化父类,再初始化子类,所以先走的父类构造,但是在执行
	父类构造时,发现父类有构造代码块,构造代码块是优先于构造方法执行的所以
	第三个输出构造代码块Fu,第四个输出构造方法Fu
	4,Fu类初始化结束,子类初始化,第五个输出的是构造代码块Zi,构造方法Zi
	*/
}
class Fu {
	static {
		System.out.println("静态代码块Fu");
	}

	{
		System.out.println("构造代码块Fu");
	}

	public Fu() {
		System.out.println("构造方法Fu");
	}
}

class Zi extends Fu {
	static {
		System.out.println("静态代码块Zi");
	}

	{
		System.out.println("构造代码块Zi");
	}

	public Zi() {
		System.out.println("构造方法Zi");
	}
}

6.重写

定义:父类和子类方法名称一样,返回值类型都一样的方法

出现情况:当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。这样,即沿袭了父类的功能,又定义了子类特有的内容,也就是功能的重新实现。

重写只有在返回的类是父类和子类的关系时,才可以。返回其他类不行。(父类子类的方法返回的是另一对父类字类)

子类重写父类方法时,权限只能更高,建议最好一样。

面试题一则:

Override和Overload的区别?Overload能改变返回值类型吗?

   方法重写:子类中出现了和父类中方法声明一模一样的方法。与返回值类型有关,返回值必须是一致的
    
   方法重载:本类中出现的方法名一样,参数列表不同的方法。与返回值类型无关。所以能改变返回值类型。

子类对象调用方法的时候:
     先找子类本身,再找父类。

7.final

    修饰类,类不能被继承(如String类)

    修饰方法,方法不能被重写

    修饰变量,变量就变成了常量,只能被赋值一次(一般搭配public final使用)

    在修饰变量的时候          修饰基本类型:值不能改变

                                             修饰引用类型:地址值不能改变,但是对象可以改变。

    说明:final student s = new student("张三",24);以后,不能再s = new student("李四",23),但是可以s.setName("李四"),s.setAge(24)。

    final修饰变量的初始化时机①显示初始化   final int num = 12;②在前面声明,在构造参数里面 num = 10;进行赋值

8.多态

事物存在的多种形态

前提:①要有继承    ②要有方法重写   ③要有父类引用指向子类对象Animal a = new Cat();(记忆方法:猫是动物。从右向左念)

多态中成员访问特点之成员变量

编译看左边(父类),运行看左边(父类)。

f输出的是10,s输出的是20。

构建出来的对象都一样,有super定义跌10,也有this定义的20,但是f左边是father,s左边是son,f只能取到super,s可以取到this。

多态中成员访问特点之成员方法

编译看左边(父类),运行看右边(子类)。

编译的时候看父类是否有该方法,运行的时候运行子类的方法,这也叫作动态绑定。(子类没有就执行父类的)

多态中成员访问特点之静态成员方法

与动态绑定相对的,他没有动态绑定。

Father f = new Son();      f.method();       看起来是用对象调用,其实是用父类Father直接调用静态方法,所以输出的肯定是父类的静态构造方法。

9.超人类说明多态本质及向上和向下转型

class Demo3_SuperMan {
	public static void main(String[] args) {
		Person p = new SuperMan();			//父类引用指向子类对象,超人提升为了人
											//父类引用指向子类对象就是向上转型
		System.out.println(p.name);
		p.谈生意();
		SuperMan sm = (SuperMan)p;			//向下转型
		sm.fly();

		/*
		基本数据类型自动类型提升和强制类型转换
		*/
		int i = 10;
		byte b = 20;
		//i = b;						//自动类型提升
		//b = (byte)i;					//强制类型转换
	}
}

class Person {
	String name = "John";
	public void 谈生意() {
		System.out.println("谈生意");
	}
}

class SuperMan extends Person {
	String name = "superMan";

	public void 谈生意() {
		System.out.println("谈几个亿的大单子");
	}

	public void fly() {
		System.out.println("飞出去救人");
	}
}

        超人在平时为了伪装自己,会说自己是个普通人(父类),在描述自己的时候,会说自己的父类的一些属性(父类的成员变量),避免暴露身份,在做事的时候,是按照超人的方式做的(自己的成员方法),但是遇到需要帮助的人时候,他需要先变身才能用超人特有的功能,结合属性的强转,他需要将普通人的身份转到范围更小的超人,所以需要强制转换,强制转换完成,他才可以使用超人的飞天等功能。

多态的向下转型在内存中的实现?

SuperMan sm = (SuperMan) p;

本质就是在栈中方法中添加一个引用SuperMan sm,和前面的Person p指向同一个堆中的new SuperMan对象,相当于同一个人换了身份。

向上转型和向下转型

父类引用指向子类对象就是向上转型

子类对象强转回子类的类就是向下转型

多态的好处

①代码的维护性(继承保证)

②代码的拓展性(多态保证)

弊端:

不能使用子类特有的属性和行为(向下转型才可以实现)

10.多态在实际开发中的应用

class Demo4_Animal {
	public static void main(String[] args) {

		method(new Cat());
		method(new Dog());

		//Animal a = new Cat();			开发的是很少在创建对象的时候用父类引用指向子类对象,直接创建子类对象更方便,可以使用子类中的特有属性和行为
	}
	
	
	//如果把狗强转成猫就会出现类型转换异常,ClassCastException
	public static void method(Animal a) {	//当作参数的时候用多态最好,因为扩展性强
		//关键字 instanceof 判断前边的引用是否是后边的数据类型
		if (a instanceof Cat) {
			Cat c = (Cat)a;
			c.eat();
			c.catchMouse();
		}else if (a instanceof Dog) {
			Dog d = (Dog)a;
			d.eat();
			d.lookHome();
		}else {
			a.eat();
		}
	}
}

class Animal {
	public void eat() {
		System.out.println("动物吃饭");
	}
}

class Cat extends Animal {
	public void eat() {
		System.out.println("猫吃鱼");
	}

	public void catchMouse() {
		System.out.println("抓老鼠");
	}
}

class Dog extends Animal {
	public void eat() {
		System.out.println("狗吃肉");
	}

	public void lookHome() {
		System.out.println("看家");
	}
}

实际的开发中,很少会父类引用指向子类对象,大部分会匿名子类作为参数,传入形参为父类的方法中,实现对应功能。

这里引入一个新的关键字:

instanceof:判断前面的引用是否属于后面的数据类型。在实际应用中判断对象是否是某个子类,在判断结束后进行向下转型,调用子类特有的方法。

11.多态分析题

class Test2_Polymorphic {
	public static void main(String[] args) {
		A a = new B();
		a.show();
		
		B b = new C();
		b.show();
	}
}
class A {
	public void show() {
		show2();
	}
	public void show2() {
		System.out.println("我");
	}
}
class B extends A {
	
	public void show2() {
		System.out.println("爱");
	}
}
class C extends B {
	public void show() {
		super.show();
	}
	public void show2() {
		System.out.println("你");
	}
}

程序原型流程分析:

    A a = new B();       a.show();

编译看父类,父类有show,可以执行。运行看子类,子类没有show,所以用继承自父类的show,相当于b中也多了一个a的show方法,show调用b的show2方法,输出爱。

    B b = new C();       b.show();

编译看父类,父类中有继承自a的show,可以运行。运行看子类,子类中的show是super,调用了b继承自a的show,还是调用c类自己的show2方法,输出你。

12.抽象

抽象类和抽象方法都用abstract修饰。abstract不能修饰变量。

抽象类不一定有抽象方法,有抽象方法的不是抽象接口就是抽象类。

抽象类不能进行实例化,一般是由它的子类进行实例化,这也是多态的一种,抽象类多态。

抽象类的子类,要么也是抽象类,要么必须重写抽象类所有的方法。

抽象类的成员特点

也有构造方法

成员变量:既可以是变量,也可以是final修饰的常量。

成员方法:可以是抽象的,强制要求子类做的事情。

                   也可以是非抽象的,子类继承的事情,提高代码的复用性。

面试题一:
 一个抽象类如果没有抽象方法,可不可以定义为抽象类?如果可以,有什么意义?
 可以
 这么做目的只有一个,就是不让其他类创建本类对象,交给子类完成


面试题二:
    abstract不能和哪些关键字共存

   ① abstract和static
    被abstract修饰的方法没有方法体,但是类名.调用抽象方法是没有意义的
    ②abstract和final
    被abstract修饰的方法强制子类重写,被final修饰的不让子类重写,所以他俩是矛盾
   ③ abstract和private
    被abstract修饰的是为了让子类看到并强制重写,被private修饰不让子类访问,所以他俩是矛盾的

13.接口

接口中的方法都是抽象的

接口不能实例化,也是通过多态的方式来实现实例化

接口的子类:

可以是具体类,但是要重写接口类中的所有抽象方法。

成员变量;只能是常量,并且是静态的并公共的。
         默认修饰符:public static final
         建议:自己手动给出。
构造方法:接口没有构造方法。
成员方法:只能是抽象方法。
         默认修饰符:public abstract
         建议:自己手动给出。

14.类和类,类和接口,接口和接口之间的关系

类和类:单继承,多层继承,不可以多继承

类和接口:实现,可以多实现(多实现即使几个接口内方法重名也不会冲突,因为每个方法内都没有具体的方法体)

接口和接口:继承,可以多继承

同种继承,不同实现。

15.抽象类和接口的区别

抽象类和普通类的区别就是抽象类可以定义抽象方法而已。

接口成员变量只能是常量,成员方法只能是抽象的。

设计理念区别在于,抽象类是基础功能,是共性,接口是拓展功能,是个性。

猜你喜欢

转载自blog.csdn.net/YooFale/article/details/82801457
今日推荐