继承-final-代码块

一.代码块

概念:使用{ }括起来的代码,称为代码块。
分类:根据它位置和声明的不同,我们可以将代码块分为局部代码块构造代码块静态代码块同步代码块(多线程涉及)。
a.局部代码块
限定了变量的生命周期,变量在局部代码块中定义的,那么出了局部代码块之后,就访问不到了。在局部代码块中定义的变量,在出了代码块之后,内存就会释放掉。
作用:主要就是节约内存。
局部代码块中定义的变量,虽然说作用域是局部的,但是如果存在外部嵌套的代码块,且在局部代码块定义之前就定义了某个变量,那么在我们局部的代码块中就不可以定义相同名称的变量。
但是如果在局部代码块执行之后,去定义了一个和局部代码块中相同名称的变量,是可以的。因为局部代码块中的变量已经失去了作用域范围。
public class Demo1{
	
	public static void main(String[] args){
		//int x = 20;					//放在代码块之前会出现编译错误,重复定义相同的变量
		{
			int x=10;		
		}
		
		int x = 20;						//放在代码块之后不会出现编译错误,因为在局部代码块中定义的变量,在出了局部代码块之后,内存就被释放掉了。
		
		System.out.println(x);	
	}
}

b.构造代码块

概念:类中方法外出现,每次调用构造方法的时候,都会优先调用构造代码块。
特点:每创建一个对象,都会调用一次我们的构造代码块。
作用:如果存在很多重载的构造方法,而且每个里面需要执行相同的逻辑,那么就可以考虑将这些代码提取到构造代码块中来执行。让代码结构更加简练。增强了维护性。(使用场景其实不太多)

c.静态代码块

概念:类中方法外出现,使用static关键字来进行修饰。
特点:随着类加载的时候执行。
用处:适用于整个软件的生命周期中,只需要执行一次的业务逻辑代码。(比如之后会用到数据库的操作
public class Demo2{
	
	static{
		System.out.println("demo2 静态代码块");	  //随着类加载的时候执行,虽然此处创建了Person类的两个对象,但只在第一次创建对象时执行一次,第二次创建对象不再执行。
	}
	
	public static void main(String[] args){
		
		Person person = new Person();
		System.out.println("--------------------");
		Person person1 = new Person(20);
	}
	
}

class Person{
	
	int age;
	
	int[] num ;				//Java语言中声明数组时不能指定其长度(数组中元素的个数),因为数组中元素的个数是在使用new创建数组对象时决定的,而不是在声明数组变量时决定的。
	
	static{
		System.out.println("调用了静态代码块");
	}
	
	{
		//构造代码块
		System.out.println("构造代码块");	//每创建一个对象,都要调用一次构造方法,在构造方法调用之前先执行构造代码块
	}
	
	//默认的构造方法
	Person(){
		System.out.println("默认构造");
		
		// 数组成员变量我们依次赋值
	}
	//带参数的构造方法
	Person(int age){
		this.age = age;
		System.out.println("非默认构造"+age);
		
		// 数组成员变量我们依次赋值
	}	
}

二.继承

特点:1.子类继承父类,继承父类的成员变量和方法。但是他们各自拥有各自的成员变量,所以他们的值,并不会继承。
           2.对于父类中的私有成员变量和私有方法,子类是无法继承的。
public class ExtendsDemo1{
	
	public static void main(String[] args){
		/*
		Father father = new Father();
		father.setName=("father");
		//father.name = "father";
		father.speak();
		*/
		
		Son son = new Son();
		//son.name = "diffo";		//当父类的成员变量name为私有时此种初始化会编译出错
		son.setName("diffo");		//当父类的成员变量name为私有时这种方式可以进行初始化
		son.speak();			//子类只继承父类的成员变量,对父类的值不继承,所以name不初始化就为null
	}
}

class Father{
	
	private int age;
	private String name;
	
	void setAge(int age){
		this.age = age;
	}
	
	void setName(String name){
		this.name = name;
	}
	
	int getAge(){
		return age;
	}
	
	String getName(){
		return name;
	}
	
	void speak(){
		System.out.println("father speak:"+name);
	}
}

class Son extends Father{
	
}
优点:a.提高了代码的复用性 
           b.提高了代码的维护性
缺点:类的耦合性增强了。
开发原则:高内聚,低耦合。
耦合:类和类之间的关系
内聚:自己独立完成某件事的能力。
3.只支持单继承,但是可以支持多层继承
继承是相互叠加的,子类继承的时候,会递归似的寻找父类中是否还存在继承,会继承整个层级直到最根部类的属性和方法。
public class ExtendsDemo2{
	
	public static void main(String[] args){
		GrandFather gFather = new GrandFather();
		gFather.speak();
		
		Father father = new Father();
		father.speak();
		father.eat();
		
		Son son = new Son();
		son.eat();
		son.sleep();
		son.speak();
	}
}

class GrandFather{
	void speak(){
		System.out.println("speak");
	}
}

class Father extends GrandFather{
	void eat(){
		System.out.println("eat");
	}
}

class Son extends Father{
	void sleep(){
		System.out.println("sleep");
	}
}
4.对于构造方法是无法继承的。但是有办法可以调用父类的构造方法。
继承关系中访问成员变量:
a.不同名的成员变量
子类可以直接访问和使用父类继承的非私有的成员变量
b.同名的成员变量
优先原则:如果子类定义了和父类中相同名字的成员变量,会优先访问子类的该变量
如果要依然访问到父类中的同名变量,我们需要加上super关键字来获取
this:当前对象的引用
super:父类对象的引用
this:可以访问到子类中的变量,也可以访问到父类中的变量
super:访问父类中的变量
public class ExtendsDemo3{
	
	public static void main(String[] args){
		Son son = new Son();
		System.out.println(son.num3);		//可以访问到子类的num3
		son.print();
	}
}

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

class Son extends Father{
	
	int num3 = 30;
	int num1 = 40;
	
	//num1是子类中定义的一个和父类同名的变量。
	void print(){
		System.out.println(this.num1+" .. "+this.num2);   //this.num1访问到的是子类的成员变量,this.num2访问到的是父类的成员变量
		System.out.println(super.num1+" .. "+super.num2); //super.num1 和super.num2访问到的是父类的成员变量
	}
}
继承关系中访问成员方法:
a.不同名的方法
子类可以直接调用到父类的方法
b.同名的方法
当父类和子类出现同名方法的时候(同名方法:指的返回值类型(父子类关系是可以的),方法名称以及方法接收的形参列表要一模一样)
在这种情况下:
当我们子类调用该方法时,会优先原则的处理,就是会先调用子类的该方法。
public class ExtendsDemo4{
	
	public static void main(String[] args){
		Son son = new Son();
		son.speak();		//会优先访问到子类的的speak();若子类没有定义同名方法,则会访问到父类的speak().
	}
}

class Father{
	
	static void speak(){
			System.out.println("father speak");
	}
	
}

class Son extends Father{
	
	void eat(){
		System.out.println("eat");
		this.speak();
	}
	
	static void speak(){
		System.out.println("son speak");
	}
	
}
方法的重写:
存在于继承关系中,子类中定义的方法和父类中的方法完全一样的时候(返回值类型父子类关系是可以的),我们在通过子类对象访问该方法的时候,就会调用到子类的方法。

方法重写的注意事项:
子类不能重写父类的私有方法。
子类重写父类方法的时候,提供的访问权限不能更低。
子类覆盖父类方法,如果父类是静态方法的话,子类也必须是静态方法才可以成功覆盖,也就是重写。
package day_06_10_15;
/*
 定义长方形类和正方形类, 正方形继承长方形并且重写计算面积和周长的方法.
*/
public class ExtensTest {

	public static void main(String[] args) {
		Rectangle rectangle = new Rectangle();
		System.out.println(rectangle.getSumLength());
		System.out.println(rectangle.getArea());
		
		Square square = new Square();
		System.out.println(square.getSumLength());
		System.out.println(square.getArea());
		
	}

}
class Rectangle{
	private double width = 4.0;		//父类的私有属性,子类不能继承
	private double height = 5.0;
	
	double getSumLength(){
		return 2*(width+height);
	}
	
	double getArea(){
		return width*height;
	}
}

class Square extends Rectangle{
	
	double lengthOfSize = 2;
	
	double getSumLength(){
		return 4*lengthOfSize;
	}
	double getArea(){
		return lengthOfSize*lengthOfSize;
	}
}
方法重载:
同一个类中,如果我们有多个相同方法名的方法,但是他们的形参是不同的,那么这种方式我们就称为方法的重载。
在调用的时候,jvm能够通过不同的形参来区分到我们到底调用的是哪个方法。

关于方法重写和方法重载的返回值约束:
方法重载:仅返回值不同是不能重载的,必须参数列表不同。
方法重写:返回值类型(父子类关系是可以的)要求返回值类型也要相同的。
this:可以访问子类的方法,也可以访问父类的方法。
super:只能够访问父类的方法。

补充:我们一个文件在编译之后产生的.class文件的数量,取决于在该文件中定义的class的数量。(非内部类),而且是不引入其他类的情况下。
继承中构造方法的调用:
特点:1.创建子类对象的时候,一定会优先去创建父类的对象。因为要创建父类对象,所以就需要去调用到父类的构造方法。
           2.对于我们所有的类的构造方法的第一行,第一行在我们没有自己添加this(...)或者super(...)的情况下都会去帮助我们默认的添加super();
            如果父类中不存在默认的构造,子类依然要创建对象,那么子类就需要显示的指明调用的是哪一个父类对象,才能保证父类对象的创建成功。
注意:
a.一定要保证父类对象的创建成功。
b.构造方法的第一行,如果我们添加了自己调用的this(...)或者super(...),系统就不会为我们默认的添加super().
c.我们的this(...)或者super(...)必须放到第一行。二者只能有其一
/*
在创建子类对象的时候,会先调用到父类的构造方法,去创建父类的对象。
*/

public class ExtendsDemo5{
	
	public static void main(String[] args){
		Son son = new Son();
		System.out.println("-------------");
	}
	
}

class Father{
	/*
	Father(){
		System.out.println("father 默认构造");
	}
    */
	
	Father(int num){
		System.out.println("father 有参构造");
	}
}

class Son extends Father{
	
	Son(){
		//super(10);
		this(10); //this(10), 所以就不会帮我们再去默认添加super(),
		System.out.println("son 默认构造");
	}
	
	Son(int num){
		super(10);
		//super(10); //第一行没有this或者super,就会帮我们添加super()
		System.out.println("son 有参构造");
	}
		
}

三.final关键字

a.final修饰类:该类不能被继承。(eg.Math类)
b.final修饰类的成员变量:该成员变量的值不可修改。

问题:那什么时候初始化这个值?
在对象创建之前都可以。
a.构造代码块中可以进行初始化
b.构造方法中可以进行初始化
c.定义成员变量的时候,可以直接进行初始化。
注意一点:这三种方式同时只能用一种
在大多数的场景下,我们的final成员变量配合public static一起使用。
//常量类, 变量命名都要大写,而且单词之间要用_分割开.
class A{
   public static final double PI = 3.14;
   public static final double RATE = 2.86;
}

A.PI
A.RATE
静态成员变量的初始化时机:
a.在创建静态final成员变量的时候,直接进行初始化。
b.在静态代码块中进行初始化。
public class FinalDemo1{
	
	public static void main(String[] args){
		Person person = new Person();
	    person.sayNum();
	}	
	
}

class Person{
	
	//final 修饰成员变量,该值不可修改.
	static final int num;
	
	static{
		num = 10;    //静态代码块中给成员变量赋初值
	}
	
	Person(){
		
	}
	
	void sayNum(){
		System.out.println(num);
	}
}
另外,学会查询使用API文档,以下是关于定义一个数组,随机方法产生随机数并对数组进行排序
import java.util.*;
/*
定义一个保存10个int 型的数组,并且初始化为 0-27 的随机值,之后进行升序排序。
*/

/*
    定义:
    method(int[] arr){
		
	}
	调用:
	int []array = new int[10];
	method(array)
	
	Arrays.sort(数组); 返回类型是void,直接输出打印会出现编译错误
	
	int[] a;
	
*/
/*
   0-9 -> *3 
*/
public class ClassTest{
	
	public static void main(String[] args){
		
		Random d = new Random();   
		
		int[] array = new int[10];
		
		for(int i=0;i<array.length;i++){
			//array[i] = (int)(Math.random()*10) * 3;
			array[i] = d.nextInt(28);
		}

		Arrays.sort(array);    //调用Array类的sort()方法进行从小到大的排序
		System.out.println(Arrays.toString(array));//将已排好序存在array数组中的数输出
	}
	
}


/*
产生10个1-10的随机数并输出打印
*/
public class MathTest{
	public static void main(String[] args){
	
	    // 1-10
		
		/*
		  0.0 -- 0.9999999999
		  0.0 -- 9.9999999
		  ǿתint: 0.0 ---- 9
		  +1
		*/
		
		for(int i=0;i<10;i++){
			//System.out.println(Math.random());
			int num = (int)(Math.random()*10)+1;
			System.out.println(num);
		}
		
	}
	
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值