第十五讲 抽象类与接口

第十五讲 抽象类与接口

1 final关键字

  • final 意为:最终的
  • 用在什么地方:

可以修饰类:被final修饰的类,是无法被继承的。因为final意为最终的。既然是最终的类,那么它就不会有子类了。

可以修饰变量:(只要是变量)它被final修饰以后,值不能被改变。也就是说,只能给final修饰的变量赋一次值,不能二次赋值。被final修饰的局部变量,生命周期结束在方法结束时,也就是说被final修饰的局部变量,仍然是一个局部变量。

final 修饰的成员变量,一定要赋初值。且只能赋一次值。(重要)

final修饰的引用类型的成员变量,也要赋初始值,且只能赋值一次。

final修饰的局部变量(方法中定义的),可以先声明,再赋值,但是只能赋一次值。

成员变量被final修饰为什么一定要初始化?成员变量是成员的,是实例对象的,如果被final修饰以后,意为该成员变量是最终的,也就是说任何一个对象看到的都是一样的东西,不能跟随对象的改变而改变了,因为它是最终的。

对象的成员属性,是对象所有的,对象不同,变量值也不一样。如果被final修饰以后,不赋初始值,那么其他的对象都有能力将该值修改一下。那么这就不是最终的了。十年前,一个对象给final修饰的成员属性赋值了,十年后又有对象修改了final修饰的成员属性值,这样的成员属性就不叫做最终的了。final失去了意义。

可以修饰方法:被final修饰的方法是不能被覆盖的

  • 常量:常量,是一个常数,比如圆周率π,它不随任何东西的改变而改变,是客观存在的。因为常数,不是变量,所以不会被改变。这种不会被改变的量,我们在定义的时候要不要每个对象都给一份?我们希望全局只有一份,而且这一份不能被改变。常量在java中应该是这个样子,只分配一次内存,且只能赋值一次。
  • 全局只有一份,在java中怎么做?static关键字修饰。因为static关键字修饰的变量在方法区内存中存在,在类加载的时候执行(分配空间),且只执行(分配空间)一次。但是被static修饰的变量,值是可以变得,内存地址只能被分配一次。我们发现final只能赋值一次,不能二次赋值。
  • 所以,java中的常量是:final + static修饰的。
    • final static double PI = 3.1415;
    • PI在方法区内存中存在,因为static修饰的在类加载的时候执行,方法区的变量生命周期是整个程序结束。
    • PI只能被赋值一次,因为被final修饰,不可能再进行二次赋值,即不能被更改
    • 常量书写的规则:单词字母全部大写,如果两个以上的单词连写,用”_”隔开
    • 常量可以被定义为private的吗?语法上是过得去的,但是情理上是过不去的,因为常量就是要被其他类访问的,因此我们不建议定义为私有的,一般情况下都定义为public的。常量是很安全的,是不可能被改变的。
  • 被final修饰的成员变量什么时候被赋值?
    • 定义的时候赋值
    • 也可以在构造方法中赋值
    • 它到底是怎样被赋值的呢?它其实是在构造方法中被赋值。如果定义的时候给了一个初始值(不是默认值),那么会在构造方法中隐式的执行这句话。
    • final int id = 10;可以被认为是这样的
      • final int id;构造方法() {this.id = 10}
    • 成员变量中被final修饰的成员变量,在有参构造中赋初始值的时候,无参构造如果存在,且未给变量赋值,编译出错。如果有无参构造且在无参构造中赋初始值,则编译通过。如果没有无参,当然是可以的。
    • final修饰的成员变量在有参构造中赋值,也只能赋值一次,这代表着构造出来的对象中被final修饰的变量是不能再次被改变的,只能赋值一次。每个对象的这个被final修饰的成员属性的值永远不能变了。好比一个人的身份证号,一旦产生就不会改变。这样的成员属性,就要加上final。每个人都有一个身份证号,只不过身份证号是不能改变的。身份证号是 一个人的成员属性,唯一且不能被改变。
public class FinalTest
{
	public static void main(String[] args) {
		//Dog d = new Dog();
		//d.id = 20;
		// 错误: 无法为最终变量id分配值
		//System.out.println(d.id);
		Animal dog = new Dog();
		// 编译时,编译器会看等号右边的引用类型,
		// 发现是Animal,那么它会去Animal中绑定Animal中所有的方法。
		// 编译器编译到dog.eat()的时候,会在Animal类中查找是否有该方法,
		// 如果有就编译通过,
		// 如果没有会向上查找,去Animal的父类Object类中找,如果找不到,编译报错
		// 这就是静态绑定
		dog.eat();
		// 运行时,JVM执行到dog.eat()的时候,
		// 会首先在子类Dog中查找是否有该方法,如果有,调用该方法。
		// 如果没有,调用父类中的该方法,如果父类中也没有,再向上找。
		// 运行时,一定找得到该方法。
		// 这就是动态绑定
		// 以上构成了多态。
	}
}


// 错误: 无法从最终Animal进行继承
//final class Animal
//{
//}

class Animal
{

//	final void eat() {};
/*
	FinalTest.java:40: 错误: Dog中的eat()无法覆盖Animal中的eat()
			void eat() {
				 ^
	  被覆盖的方法为final
*/
// 也就是说,当final修饰成员方法的时候,该方法不能被重写。
}

class Dog extends Animal
{
	final int id = 10;

	void eat() {
		System.out.println("小狗吃骨头");
	}
/*
	void test() {
		final int k =10;
		// 错误: 无法为最终变量k分配值
	}

	void test01() {
		System.out.println(k);//错误: 找不到符号
		// 也就是说,被final修饰的局部变量,生命周期结束在方法结束时。
		// 也就是说被final修饰的局部变量,仍然是一个局部变量。
	}
*/	
}

2 权限修饰符

  • public
  • protected
  • private
  • 缺省的
public: 公开的
protected :受保护的
缺省的: 没有加上修饰符
private : 私有的
权限修饰符用在什么地方:
    修饰类:只能是public或者是却省的,不能使用privateprotected来修饰
    修饰成员变量:protected修饰的成员变量,在类外是可以被访问的 (前提是在同一个包中)protected修饰的成员变量可以在子类中访问。默认的也可以在子类中被访问。
    修饰成员方法

    
  package的概念:包,文件夹、目录
    在java中,我们在写代码的时候,不能将所有的代码都写在一起,这样的话后期的工作量很大。于是就有了包的概念。
    同类型的代码我们放在同一个包里。不同类型的代码放在不同的包里。这样业务上就更加清晰了。
    
E:\java基础\day08-1-29\com\tj>java MyTest
错误: 找不到或无法加载主类 MyTest
原因: java.lang.NoClassDefFoundError: com/tj/MyTest (wrong name: MyTest)
    
    这个因为,package的概念是指,一个包名+类名 才是一个完整的类名。
    也就是说一个类的真正的完整的名字,不是class后面所带的那个标识符,而是整个包名+类名。
    包名的书写:com.xxx.xxxx.xxx这种方式一般是公司的域名倒着写
    www.baidu.com
    com/baidu/www 包的目录结构
    com.baidu.www 这是包名
    完整的类名:com.baidu.www.Test;
在java中package的语法如下:package跟上全路径名,然后以";"结尾
	package com.tj.pojo;
	package 这个关键字一定要出现在java源文件的第一行(注释不算)
        
        
import com.tj.pojo.User;
	import 关键字:导包
        它的作用是可以在不同的包中引用类。
        import关键字的语法:import 全路径名.类名;
	import com.tj.pojo.*;
	"*"代表该包下所有的类
访问控制修饰符本类子类同包任意位置
publicYYYY
protectedYYYN
默认YN(Y)YN
privateYNNN
  • 今天讲的内容不多,引导你们学习的方法,就是遇到了一些关键字、语法的时候,要自己去测试,变着法儿的测。

3 抽象类

  • 什么是抽象类

    • 类:是对对象进行抽象的结果,是一个抽象的概念,一类事物共有的属性和方法的集合。

    • 抽象类:对类进行抽象的结果。抽象之上的抽象。

    • 比如说:大学生是一个类,xjf是一个大学生,xjf是一个对象,我们大家都要是大学生这个类下的对象。大学生、中学生、小学生共同抽象出一个类叫做学生类。学生这个类就可以被看成是抽象类。

    • 怎么定义抽象类:

      • 在类定义之前,class之前加上abstract
      • 抽象类无法创建对象;
      • 抽象类有构造方法吗?有
      • 构造方法有什么用呢?首先要回答抽象类有什么用?抽象类可以被继承。那么它的构造方法就是为了给子类对象构造父类型的特征。
      • 一个类没有办法创建对象,那么这个类只能有一个作用了,这个作用就是只能被继承,只能当父类啊!!!
      • 抽象类是无法实例化的。抽象类中,就有抽象的方法。抽象的方法就是没有方法体。如果有方法体就是具体的方法了。
      • 抽象方法的定义:[访问权限修饰符] abstract [返回值类型] 方法名();
      • private与abstract是无法结合使用的。抽象出来的方法一定要在其他地方具体化(具体化是要有对象的,对象只能在子类中存在。这是对象相关的方法。),如果把这个抽象的东西变成了私有的,请问如何私有化?所以不能这么用。
      • abstract不能与private、static、final等组合使用。final修饰的方法是最终的方法,是不能被继承的方法。抽象方法就是用来被子类继承且被重写。其实抽象方法是完完全全要交给子类去定义的。因为抽象方法没有方法体,只有方法头(返回值类型 方法名(参数列表);)
      • abstract修饰的方法一定要子类重写。子类一定要覆盖。否则编译报错。为什么报错?猜!!!
        • 1.继承的本质是为了多态服务的
        • 2.如果子类不去重写抽象父类中的抽象方法,多态是怎样的?动态绑定的时候就要去执行父类中的方法,父类中的方法没有方法体,怎么执行呢?静态绑定的时候,它会在父类中找可以执行的方法,发现没有方法体啊!报错。
        • 抽象方法不能有方法体。也就是说方法名()后面不能带有{}
        • 抽象方法一定要被子类重写。。。。
    • 不是抽象类中能否有抽象方法?不能。抽象方法只能存在于抽象类中。

    • 一个抽象类中,可以没有抽象方法。有抽象的方法类一定要被定义为抽象类。

  • 总结:

    • 抽象类无法实例化对象。
    • 抽象类中的抽象方法一定要被子类重写。
    • 抽象方法和空方法的区别,抽象方法没有方法体{};空方法是有{}只不过{}中没有内容,也不被abstract修饰。

4 接口(interface)

  • 什么是接口?
    • 接口就是方法抽象的集合。抽象类是类的抽象,类是对象的抽象。对象包含属性和方法。
    • 接口就是对方法的抽象
    • 语法:
    • interface 接口名(){}
    • 接口也是一个java文件,编译后生成的也是.class文件
    • 接口中的方法写成:返回值类型 方法名();
    • 如果在接口中的方法前加上abstract修饰,也没问题。因为本身接口中的方法都是抽象的。
    • 接口抽象方法不能带有主体。也就是收接口中的方法本身就是抽象的,所以不能带主体。
    • 接口中的方法可以用哪些访问权限修饰符来修饰?只能用public或者是默认的。其实默认的在这里可以被理解问public的。因为它都是公开的,没必要写。
    • 接口中还可以定义其他的属性吗?可以,但必须要给属性赋值。什么情况下必须要给属性赋值啊?????接口中没有构造方法,成员属性一定要赋值,怎么办?static。static根本就不需要构造方法,它是在类加载的时候赋值的。必须要赋值,又是static的,请问这是什么东西?常量。
    • 所以:接口中只能定义常量。不能定义其他成员变量。常量前面修饰可以省略,类型不能省。final static是可以省略的。
  • 接口怎么用
    • 普通的类无法继承接口:因为接口没有构造方法,所以不能成为父类,子类无法通过父类的构造器构造父类的特征。
    • 接口之间是可以继承的,而且可以多继承。多继承之后,还不能重写父接口中的方法。假如要重写,就不再是接口了,而是子类了。
    • 接口怎么用呢?implements
      • class ABC implements A:类ABC实现接口A
      • 既然是实现,实现什么?只能实现其中的方法吧。因为接口中的方法都是没有实现的,只是纯抽象的方法。必须要有类去实现它,才有意义。
      • 实现类实现接口的时候,一定要加上public访问权限修饰符
      • 类ABC一但实现接口A,就必须要实现A中所有的抽象方法。否则编译报错。
    • 接口和抽象类,都是引用类型。也就是说:abstract 还是 interface限定的,他们都是不能实例化对象的,但是他们都是引用类型。
public interface A
{
	static int i = 10; // 编译通过,这只有一个解释,省略了final
	//final static String COUNTRY = "CHINA";// 这是常量的定义。
	String COUNTRY = "CHINA";// 这里省略了final static关键字。只有接口中可以这么做。

	void a1();
	public abstract void a2();
} 

interface B
{
}


interface C extends A,B
{
	void a1();
}

class ABC implements A,B,C
{
	public void a1() {}
	public void a2() {
		System.out.println("ABC------");
	}

}

class Test
{
	public static void main(String[] args){
		A a = new ABC();// 父类型引用指向子类型对象。静态绑定是不是通过了?
		// 我们以前说过,多态的发生依赖于继承和重写。有了继承才有了父类型引用指向子类型对象
		// 有了重写,才让动态绑定发生。才有了多态,编译时一种形态,运行时另一种形态
		// 我们再看继承:extends,意为继承吗????扩展!!!
		// 什么扩展,以前很窄咯,现在要扩宽咯。以前的功能不够强大咯,现在要变得更强大咯。
		// 继承的本质是不是就是扩展啊!!子类要拥有父类所有的东西,又要比父类强大。
		// 这才是我说继承时候,说过的“青出于蓝而胜于蓝”的真正含义。
		// 父类中的方法,不够强大,不能满足业务要求,子类就有权力去重写它。
		// 接口中的方法就很强大吗?接口中定义的都是抽象方法,说白了就是一个名字而已,要啥没啥。
		// 接口中的方法就是一个简单的规定啊!它没有太大的作用。它真正的意义就是告诉实现类
		// 你要按照我接口中的方法的标准去写。这样使得大家都遵守接口的规定。
		// 接口就是一种规范。具体的实现交给实现类。实现类对接口中方法的实现就是扩展。
		// 所以,我们也将实现类实现接口中的方法看成是某种意义上的继承。
		// SUN公司java开发人员把多态的机制也引入到了接口中。
		// 所以接口也是引用类型,我们也可以将它用于多态
		// 实现类可以多实现接口,也就是说一个实现类可以实现多个接口
		// 接口的总结:它是一种规范,它可以用于多态,它是引用类型,它的引用可以指向实现类的对象。
		a.a2(); 
		// 以上两句话是什么?多态!!!!!!
        // 多态才是面向对象的真正的核心。
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值