java基础三(继承)

java面向对象三大特性,封装、继承、多态。上一节中我们已经学习了有关封装的知识,接下来我们来学习继承。

1.概念
  1.1一种类与类之间的关系
  1.2使用已存在的类的定义作为基础建立新类
  1.3新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。
  1.4满足"A is a B"的关系
2.特点:
  2.1利于代码复用
  2.2缩短开发周期
3.语法:
  3.1 使用extends实现继承
  3.2 单一继承,只能有一个父类。(如:狗继承动物,动物称作父类或基类,狗称作子类或派生类)

  3.3子类只能继承自父类的非私有成员,父类不可以访问子类的特有成员

  3.4语法规则:返回值类型、方法名、参数类型、顺序、个数都要与父类继承的方法相同。

4.继承后的初始化顺序:

父类静态成员——>子类静态成员——>父类对象构造——>子类对象构造


5.学习方法重写的知识,并比较:方法重载与方法重写

* 方法重写
      * 1) 有继承关系的子类中
      * 2) 方法名相同,参数列表相同(参数顺序、个数、类型),方法返回值相同
      * 3) 访问修饰符,访问范围需要大于等于父类的访问范围
      * 4) 与方法的参数名无关
* 方法重载:
      * 1) 同一个类中
      * 2) 方法名相同,参数列表不同(参数顺序、个数、类型)
      * 3) 方法返回值、访问修饰符任意
      * 4) 与方法的参数名无关

注:方法重写存在,属性重写不存在。

       虽然重写仅限于方法上面,但是在子类中,可以定义与父类重名的属性的。


6.访问修饰符

公有的:public  允许在任意位置访问
私有的:private  只允许在本类中进行访问
受保护的:protected  允许在当前类、同包子类/非子类、跨包子类调用。跨包非子类不允许
默认: 允许在当前类,同包子类/非子类调用。跨包子类/非子类不允许调用。

即满足这样的关系

访问修饰符本类同包子类其他
private   
默认  
protected 
public

7.如何区分调用的是父类的继承父类的方法,还是子类自己重写的方法?

——接下来我们学习和使用super关键字

7.1 super:父类对象的引用

注:1.父类的构造不允许被继承、不允许被重写,但是会影响子类对象的实例化过程。

       2.继承后的初始化顺序:
         父类静态成员——>子类静态成员——>父类对象构造(属性(赋值)、构造代码块、构造方法)——>子类对象构造(属性(赋值)、构造代码块、构造方法)

7.2 super的使用:
1)子类构造默认调用的父类的无参构造方法;

  除了父类和子类的无参构造方法,我们也拥有一个父类和子类的双参构造,但是即使是这样,在我们进行调用的时候,默认的顺序仍然是:父类的静态代码块、子类的静态代码块、父类的构造代码块、父类的无参构造方法、子类的构造代码块、子类的带参构造方法

(注:具体的执行流程,可以在断点调试中详细观察。下面直接贴出运行结果)

package com.susu.animal;

//父类
public class Animal {

	private String name = "妮妮";// 昵称
	protected int month;// 月份
	String species = "动物";// 品种

	static {
		System.out.println("我是父类的静态代码块");
	}

	public static int st2 = 23;
	private static int st1 = 22;

	{
		System.out.println("我是父类的构造代码块");
	}

	// 父类的构造不允许被继承、不允许被重写,但是会影响子类对象的实例化
	 public Animal() {
		System.out.println("我是父类的无参构造方法");
	}

	public Animal(String name, int month) {
		this.name = name;
		this.month = month;
		System.out.println("我是父类的带参构造方法");
	}
package com.susu.animal;
//子类
public class Cat extends Animal{
	private double weight;//体重
	public static int st3=44;
	
	static{
		System.out.println("我是子类的静态代码块");
	}
	
	{
		System.out.println("我是子类的构造代码块");
	}
	
	public Cat(){

		System.out.println("我是子类的无参构造方法");
	}
	
	public Cat(String name,int month){
		System.out.println("我是子类的带参构造方法");
	}
package com.susu.animal;
//测试类
public class Test {

	public static void main(String[] args) {
		Cat one = new Cat();
		/*
		 *  我是父类的静态代码块
			我是子类的静态代码块
			我是父类的构造代码块
			我是父类的无参构造方法
			我是子类的构造代码块
			我是子类的无参构造方法
		 */

		Cat two = new Cat("xinxin",12);
		/*我是父类的静态代码块
		我是子类的静态代码块
		我是父类的构造代码块
		我是父类的无参构造方法
		我是子类的构造代码块
		我是子类的带参构造方法*/
	}
}

 通过以上代码的运行结果,我们可以清楚的看到,不管是子类调用是带参还是无参,都会默认调用父类的无参构造,而不是带参构造。那么如果我们非要调用父类的带参构造呢?下面我们来看第二点。

2)我们可以通过super()调用父类允许被访问的其他构造方法;

  我们写一个父类和子类的双参构造,如果想要调用双参构造方法,我们只需要把参数传进来就好。如:super(name,month),当进入子类双参构造时,由于super(name,month)的存在,会进入父类的双参构造,完成我们期待的指定构造方法的调用。

  即顺序:父类的静态代码块、子类的静态代码块、父类的构造代码块、父类的带参构造方法、子类的构造代码块、子类的带参构造方法

为了更好的证明这一点,我们把修改后的代码,以及运行结果贴出来:

package com.susu.animal;

//父类
public class Animal {

	private String name = "妮妮";// 昵称
	protected int month;// 月份
	String species = "动物";// 品种

	static {
		System.out.println("我是父类的静态代码块");
	}

	public static int st2 = 23;
	private static int st1 = 22;

	{
		System.out.println("我是父类的构造代码块");
	}

	// 父类的构造不允许被继承、不允许被重写,但是会影响子类对象的实例化
	 public Animal() {
		System.out.println("我是父类的无参构造方法");
	}

	public Animal(String name, int month) {
		this.name = name;
		this.month = month;
		System.out.println("我是父类的带参构造方法");
	}
package com.susu.animal;
//子类
public class Cat extends Animal{
	private double weight;//体重
	public static int st3=44;
	
	static{
		System.out.println("我是子类的静态代码块");
	}
	
	{
		System.out.println("我是子类的构造代码块");
	}
	
	public Cat(){

		System.out.println("我是子类的无参构造方法");
	}
	
	public Cat(String name,int month){
        /* 子类构造默认调用父类无参构造方法
		 * 可以通过super()调用父类允许被访问的其他构造方法
		 * super()必须放在子类构造方法有效代码第一行
		 */
		super(name,month); //this
		System.out.println("我是子类的带参构造方法");
	}

 

package com.susu.animal;
//测试类
public class Test {

	public static void main(String[] args) {
		Cat three = new Cat("xinxin",12);
		/**
		 * 	我是父类的静态代码块
			我是子类的静态代码块
		 * 	我是父类的构造代码块
			我是父类的带参构造方法
			我是子类的构造代码块
			我是子类的带参构造方法
		 */
	}
}

 以上代码只是在原有代码的基础上,做了一点点的修改,就产生了我们预期的效果。实际上,我只在Cat类的双参构造中,添加了一行语句,super(name,month),从而调用父类允许被访问的其他构造方法。

3)super()必须放在子类构造方法有效代码第一行。

public Cat(String name,int month){
		/* 子类构造默认调用父类无参构造方法
		 * 可以通过super()调用父类允许被访问的其他构造方法
		 * super()必须放在子类构造方法有效代码第一行
		 */
		super(name,month);  //放在了第一行。如果放在其他行,如打印语句的下面,会报错。
		System.out.println("我是子类的带参构造方法");
	}

7.3 super知识的总结:
super:代表父类引用

子类访问父类成员:
    -访问父类成员方法   super.print()
    -访问父类属性    super.name;
    -访问父类构造方法  super();
   注:1.子类的构造的过程中必须调用其父类的构造方法
        2.如果子类的构造方法中没有显示标注,则系统是默认调用父类无参的构造方法
        3.如果子类构造方法中既没有显示标注,且父类中没有无参的构造方法,则编译出错。
        4.-使用super调用父类指定构造方法,必须在子类的构造方法的第一行       
7.4 比较this和super

this: 当前类对象的引用super:父类对象的引用
-访问当前类的成员方法
-访问当前类的成员属性
-访问当前类的构造方法
-不能在静态方法中使用
-访问父类的成员方法
-访问父类的成员属性
-访问父类的构造方法
-不能在静态方法中使用
public Cat(String name,int month){
        /* 子类构造默认调用父类无参构造方法
         * 可以通过super()调用父类允许被访问的其他构造方法
         * super()必须放在子类构造方法有效代码第一行
         */
         //this();
        super(name,month); //this
        System.out.println("我是子类的带参构造方法");
    }

注: 构造方法调用时,super和this不能同时出现。因为super和this有很多的相似之处,二者都要抢占Cat带参构造中的第一行有效代码,因此放一块时,会产生矛盾。如果强制写上去,不管谁在上面,程序都会报错。


8. Object类

  1)Object类是所有类的父类

  2)   一个类没有使用extends关键字明确标识继承关系,则默认继承Object类(包括数组)
  3) Java中的每个类都可以使用Object中定义的方法

   以下是子类当中重写父类概率比较高的方法:

      /*toString:
         * 1、输出对象名时,默认会直接调用类中的toString
         * 2、继承Object中的toString方法时,输出对象的字符串表示形式:类型信息+@+地址信息
         * 2、子类可以通过重写equals方法的形式,改变输出的内容以及表现形式
         */

      /*equals:
         * 1、继承Object中的equals方法时,比较的是两个引用是否指向同一个对象
         * 2、子类可以通过重写equals方法的形式,改变比较的内容
         */

                                        Object类中的常用方法

方法说明
toString()返回当前对象本身的有关信息,按字符串对象返回
equals()比较两个对象是否是同一个对象,是则返回true
hashCode()返回该对象的哈希代码值
getClass()获取当前对象所属的类信息,返回Class对象

 

我们来区分以下代码

代码1: public boolean equals(Object obj)

               属于重写Object类的equals方法,因此参数类型是Object,需要强转为Animal类。

代码2: public boolean equals(Animal obj)  限制了传入参数类型是Animal,避免了类型转换有可能出现的异常。但相对于上面重写父类Object的equals方法而言,属于方法的重载。是针对Animal类中的equals方法产生的重载方法。二者之间的区别大家要区分开来。

       public boolean equals(Object obj){
  		if(obj==null)
			return false;
		Animal temp=(Animal)obj;
		if(this.getName().equals(temp.getName()) && (this.getMonth()==temp.getMonth()))
				return true;
		else
			return false;
	}
	
	public boolean equals(Animal obj){
	    if(obj==null)
			return false;
		if(this.getName().equals(obj.getName()) && (this.getMonth()==obj.getMonth()))
				return true;
		else
			return false;
	}

 


9. final

/* final 修饰class:该类没有子类  public final class \ final public class
 * final 修饰方法:该方法不允许被子类重写,但是可以正常被子类继承使用
 * final 修饰方法内局部变量:只要在具体被使用之前进行赋值即可,一旦赋值不允许被修改
 * final 修饰类中成员属性:赋值过程:1、定义直接初始化  2、构造方法中赋值  3、构造代码块中赋值
                       (否则会报错)
 */

ps: java基本数据类型:int  float  double ...等

      java引用数据类型:类、String  System  数组...等    eg. Animal a = new Animal();

      那么,我们进行思考?像引用数据类型的变量一旦被final修饰后,它的引用地址是否可以发生改变,里面的属性值是否可以发生改变呢?我们可以通过代码来验证。

public void eat(String name) {
	
		final Animal animal=new Animal("xinxin",1);
//		animal=new Animal();
	}

代码animal = new Animal(); 会报错,则说明不能修改它的引用。那么属性呢?依然以代码为例。

public void eat(String name) {
		
		final Animal animal=new Animal("xinxin",1);
//		animal=new Animal();
		animal.month=1;
		animal.name="ss";
	}

 我们看到,属性是可以被赋值的。综上,用final修饰的引用类型的变量,在实例化之后,就不允许再进行引用地址的修订,但是引用对象的属性值可以根据我们的需要进行修改。

final总结:

1)修饰类表示不允许被继承
2)修饰方法表示不允许被子类重写
    - final修饰的方法可以被继承
    - 不能修饰构造方法
3)修饰变量表示不允许修改
   方法内部的局部变量:在使用之前被初始化赋值即可。
   类中成员变量: 只能在定义时或者构造代码块、构造方法中进行初始化设置。
   基本数据类型的变量:初始赋值之后不能更改
   引用类型的变量:初始化之后不能再指向另一个对象,但指向的对象的内容是可变的。
4)可配合static使用
5)使用final修饰可以提高性能,但会降低可扩展性


10.注解的分类

按照运行机制分:

1) 源码注解: 注解只在源码中存在,编译成.class文件就不存在了。

2) 编译时注解: 注解在源码和.class文件中都存在

3) 运行时注解: 指的是在运行阶段还起作用,甚至会影响运行逻辑的注解。如Spring注解:@Autowired

按照来源分:

1) 来自JDK的注解

2) 来自第三方的注解

3) 我们自己定义的注解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值