(一)instanceof关键字
instanceof关键字:判断一个对象是否属于指定的类型。
使用前提:判断的对象与指定的类型必须存在继承关系,或者是实现的关系。
使用格式:
对象 instanceof 类名
(二)final关键字
final关键字要注意的细节:
1.final关键字修饰一个基本类型变量时,该变量不能重新赋值(常量)。
2.final关键字修饰一个引用类型变量时,其引用不能重新指向新的对象。
3.final修饰一个方法时,该方法不能被重写。
4.final修饰一个类,该类不能被继承。
常量的修饰符:public static final
常量命名规则:所有字母大写,单词与单词之间下划线分隔。
不同方法中的局部变量是相互独立的,互不干涉。
(三)abstract类
abstract抽象类的应用场景:
描述一类事物的时候,发现该事物确实存在着某种行为,但是目前该行为是不具体的。
那么这时候我们应该抽取该方法的声明,不去实现该方法,使用抽象类实现。
抽象类要注意的细节:
1.如果一个方法没有方法体,那么该方法必须用abstract修饰。
2.如果一个类有抽象的方法,那么该类也必须使用abstract修饰。
3.非抽象类继承抽象类的时候,必须要把抽象类中的所有抽象方法全部实现。
4.抽象类可以定义抽象方法以及非抽象方法。
5.抽象类是可以不存在抽象方法的。(语法上允许,但是一般不这样用)
6.抽象类无法实例化,即不能创建对象。
原因:抽象类一旦创建对象,就可以使用对象调用方法,一旦调用了抽象方法,就没有任何意义了。
7.抽象类是存在构造方法的。
疑问:既然抽象类不能创建对象,那么存在构造方法的意义何在呢?
抽象类的构造方法是留给子类初始化从父类继承下的属性。
例如:
abstract class Animal
{
String name;
String color;
public Animal(String name,String color){
this.name=name;
this.color=color;
}
//移动 抽象方法,没有{}
public abstract void run();
//非抽象方法 可以定义在抽象类中
public void sleep(){}
}
class Dog extends Animal
{
public Dog(String name,String color){
super(name,color);
}
public void bite(){
System.out.println(name+"在汪汪叫");
}
public void run(){
System.out.println(name+"四条腿跑得快...");
}
}
class Bird extends Animal
{
public Bird(String name,String color){
super(name,color);
}
public void fly(){
System.out.println(name+"飞得更高~");
}
public void run(){
System.out.println(name+"两条腿跑得不太快...");
}
}
class demo3
{
public static void main(String[] args)
{
Dog d=new Dog("牛头梗","粉色");
d.bite();
d.run();
//System.out.println("Hello World!");
Bird b=new Bird("喜鹊","彩色");
b.fly();
b.run();//父类的功能无法满足子类的需求,方法重写
Animal a=new Animal("动物","黑色");
}
}
anstract不能与以下关键字配合使用:
1.abstract不能与private配合使用。
abstract表示在本类中声明,在子类中必须实现,但是private规定只能在本类可见,矛盾。
2.abstract不能与final关键字配合使用。
abstract表示在本类中声明,在子类中必须实现,但final修饰的方法是最终方法,不允许别人实现或重写,矛盾。
3.abstract也不能和static配合使用。
static修饰的方法可以用类名直接调用,但是abstract修饰的方法调用没有意义。
(四)值交换
值交换:调用一个方法时,传递给方法的是变量所存储的值。
两个函数之间的变量肯定是独立的,互不干涉。操作是否会有影响,是看操作的是不是同一个对象,即是不是引用类型变量。
例如:
import java.util.*;
class Person
{
int x;
public Person(int x){
this.x=x;
}
}
class demo6
{
public static void main(String[] args)
{
/*
int a=6;
int b=10;
change(a,b);
System.out.println("a="+a+"b="+b);//a=6 b=10
*/
/*
int[] arr={10,20,30};
changeArr(arr,0,2);
System.out.println("交换之后的值:"+Arrays.toString(arr));//30 20 10
*/
Person p=new Person(10);
changeObj(p);
System.out.println("交换之后的值:"+p.x);//20
}
//定义一个函数交换数组的元素的位置
public static void changeArr(int[] arr,int id1,int id2){
int temp=arr[id1];
arr[id1]=arr[id2];
arr[id2]=temp;
}//虽然两个arr变量相互独立,但是操作的是同一个对象,所以有影响。
//定义一个函数交换两个变量的值
public static void change(int a,int b){//形参是局部变量,局部变量之间相互独立,基本类型的变量之间相互不影响,就近原则
int temp=a;
a=b;
b=temp;
System.out.println("a="+a+"b="+b);//a=10 b=6
}
//定义一个方法改变对象的属性值
public static void changeObj(Person p){
p.x=20;
}
}
(五)接口
接口:
定义格式:
interface 接口名{
}
实现接口的格式:(类实现了接口)
class 类名 implements 接口{
}
接口要注意的细节:
1.接口其实是一个特殊的类。
2.接口中的成员变量都是属于常量(常量没有默认初始值,必须初始化),默认修饰符是 public static final,如果不写,java编译器会自动添加
3.接口中的函数都是抽象函数,默认修饰符是public abstract
4.接口是不能用于创建对象的,函数都是抽象函数,没有调用的意义。
5.接口中没有构造方法,因为接口中都是常量和抽象函数,不存在初始化。
6.一个非抽象类实现一个接口时,必须实现接口中所有函数。
接口的作用:(按重要性排序)
1.程序解耦。(低耦合)
2.定义约束规范。
3.拓展功能。
例如:
interface raiseMoney
{
public void raise();
}
class Student
{
String name;
int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
public void study(){
System.out.println(name+"好好学习!!");
}
}
class PartTimeStudent extends Student implements raiseMoney//部分会挣钱的学生
{
public PartTimeStudent(String name,int age){
super(name,age);
}
public void raise(){
System.out.println(name+"挣到钱啦,好开心!!!");
}
}
class work1
{
public static void main(String[] args)
{
PartTimeStudent s1=new PartTimeStudent("小明",20);
s1.study();
s1.raise();
Student s2=new Student("小红",19);
s2.study();
//s2.raise();
}
}
java只允许单继承,即一个子类只能有一个父类。
接口与类之间的关系:实现关系。
要注意的细节:
1.非抽象类实现接口时,必须要把接口中所有方法实现。
2.一个类可以实现多个接口。
疑问:java支持多实现接口,为什么不支持多继承呢?
因为如果支持多继承的话,假设多个父类中有相同的成员,那么子类不知道到底继承哪一个。
3.抽象类实现接口的时候,可以实现接口中的方法,也可以不实现。
接口与接口之间的关系:继承关系。
要注意的细节:
1.一个接口可以继承多个接口。
(六)多态
多态:
父类引用类型变量指向子类的对象或者是接口的引用类型变量指向了接口实现类的对象。(一个对象具备多种形态。)
多态的前提:
必须存在继承或者实现关系。
多态要注意的细节:
1.多态情况下,子父类存在同名的成员变量,默认访问的是父类的变量。
2.多态情况下,子父类存在同名的非静态成员函数时,访问的是子类的函数。
3.多态情况下,子父类存在同名的静态成员函数时,访问的是父类的函数。
4.多态情况下,不能访问子类特有的成员函数。
原因:java编译器的编译原理中有句话:编译看左边,运行不一定看右边。
编译看左边:java编译器在编译的时候,会检查引用类型变量所属的类是否具备指定的成员,若不具备,编译报错。
总结:多态情况下,子父类存在同名的成员时,默认都会访问父类的成员,只有存在非静态的同名函数时,才是访问子类的成员。
例如:
abstract class Animal
{
String name;
String color;
int age=10;
public Animal(String name,String color){
this.name=name;
this.color=color;
}
//移动 抽象方法,没有{}
public abstract void run();
//非抽象方法 可以定义在抽象类中
public static void sleep(){
System.out.println("睡得好香");
}
}
class Dog extends Animal
{
int age=20;
public Dog(String name,String color){
super(name,color);
}
public void bite(){
System.out.println(name+"在汪汪叫");
}
public void run(){
System.out.println(name+"四条腿跑得快..."+age);//访问的是子类age
}
public static void sleep(){
System.out.println("睡得不香");
}
}
class Bird extends Animal
{
public Bird(String name,String color){
super(name,color);
}
public void fly(){
System.out.println(name+"飞得更高~");
}
public void run(){
System.out.println(name+"两条腿跑得不太快...");
}
}
class demo10
{
public static void main(String[] args)
{
Animal a=new Dog("哈士奇","白色");//多态 父类的引用类型变量指向了子类的对象
a.bite();
System.out.println(a.age);
}
}