1、super关键字
super 关键字的作用,访问父类成员
super.属性名 //访问父类属性
super.方法名() //访问父类方法
super(参数列表) //访问父类的构造方法
(1)用super调用父类的构造方法
要构造子类,必须先构造父类 //要执行子类的构造方法,必须先执行父类的构造方法
class Parent{
}
class Son extends Parent{
}
实际上,这段代码会被处理成:
//如果不声明继承谁,就相当于继承自Object
class Parent extends Object{
//如果我们不提供构造方法,系统会帮我们生成一个默认的
public Parent() {
//如果我们不显示的调用父类的构造方法,系统会帮我们调用
super();
}
}
class Son extends Parent{
public Son() {
super();
}
}
由以上知识点可以作为一个考察点,比如
class Parent{
public Parent(String name) {
}
}
class Son extends Parent{
public Son() {
super(); //报错
}
}
//又或是以下这种写法
class Son extends Parent{ //报错
}
这是因为当子类调用super()时试图调用父类的无参构造方法,或不调用时系统默认的调用父类的无参构造方法,这两种情况都会编译出错,因为父类没有无参的构造方法,要想修正
方法一:给父类加一个无参的构造方法
方法二:明确的在子类的构造方法中,用super(参数)的方式指明调用父类的某个构造方法
class Parent{
public Parent(String name) {
}
}
class Son extends Parent{ //报错
public Son() {
super("张三");
}
}
(2)super()必须放在子类构造方法的第一行
比如
class Machine{
String productor;
String name;
Machine(String productor,String name){
this.productor=productor;
this.name=name;
}
}
class Computer extends Machine{
String cpu;
int disk;
Computer(String productor,String name,String cpu,int disk){
super(productor,name); //调用父类的构造方法
this.cpu=cpu;
this.disk=disk;
}
}
(3)为什么this()和super()在子类的同一个构造方法中不能同时存在
因为this()必然引起本类中其他的构造方法的执行,这个其他的构造方法的第一句,也必然是super(...)
(4)为什么this()这个动作,必须放在构造方法的第一行
因为this()这个动作会调用本类的其他构造方法,其他构造方法第一句必然是super(),由于super()需要放在第一句,所以this()也需要放在构造方法的第一句,比如
class Machine{
String productor;
String name;
Machine(String productor,String name){
this.productor=productor;
this.name=name;
}
}
class Computer extends Machine{
String cpu;
int disk;
Computer(String productor,String name,String cpu,int disk){
// super(productor,name); //this()和super()不能同时出现在一个构造方法里
this(productor,name,cpu); //必须放在第一行
this.disk=disk;
}
Computer(String productor,String name,String cpu){
super(productor,name);
this.cpu=cpu;
}
}
2、重写和多态
重写:override 发生在父子类之间 方法的签名相同(方法名,参数个数和类型,返回值类型)
重载:overload 发生在同一个类中 方法名相同,参数个数和类型有所不同,不关心返回值
多态:主要体现在,在定义方法参数的时候,用基类定义传参的时候可以传入这个基类的子类,运行的时候,表现出来的是不同的子类的行为,这就称为多态,比如
public class Test3 {
public static void main(String[] args) {
Student stu = new Student();
talk(stu);
PrimarySchoolStudent psstu = new PrimarySchoolStudent();
//或写成Student psstu = new PrimarySchoolStudent();用基类的引用指向子类对象
talk(psstu);
UniversityStudent ustu = new UniversityStudent();
//或写成Student ustu = new UniversityStudent();用基类的引用指向子类对象
talk(ustu);
/**
* 输出为:
* 和学生交谈
我是学生
和学生再见
和学生交谈
我是小学生
和学生再见
和学生交谈
我是大学生
和学生再见
*/
}
static void talk(Student student) {
System.out.println("和学生交谈");
student.say();
System.out.println("和学生再见");
}
}
class Student{
void say() {
System.out.println("我是学生");
}
}
class PrimarySchoolStudent extends Student{
void say() {
System.out.println("我是小学生");
}
}
class UniversityStudent extends Student{
void say() {
System.out.println("我是大学生");
}
}
多态的好处:
①提高了方法的可重用性,程序更精简
②提高了方法的向后兼容性
3、对象的类型转换
public class Test3 {
public static void main(String[] args) {
Student stu = new Student();
talk(stu);
PrimarySchoolStudent psstu = new PrimarySchoolStudent();
//或写成Student psstu = new PrimarySchoolStudent();用基类的引用指向子类对象
talk(psstu);
UniversityStudent ustu = new UniversityStudent();
//或写成Student ustu = new UniversityStudent();用基类的引用指向子类对象
talk(ustu);
/**
* 输出为:
* ================
我是学生
================
我是小学生
================
我是大学生
学习数据库
*/
}
static void talk(Student student) {
System.out.println("================");
student.say();
if(student instanceof UniversityStudent) {
((UniversityStudent)student).study();
}
}
}
class Student{
void say() {
System.out.println("我是学生");
}
}
class PrimarySchoolStudent extends Student{
void say() {
System.out.println("我是小学生");
}
}
class UniversityStudent extends Student{
void say() {
System.out.println("我是大学生");
}
void study() {
System.out.println("学习数据库");
}
}
注意:对象的类型转换,要求必须是本类的示例才能转换,否则会出现ClassCastException异常
4、Object类
是Java类中最顶层的类,所有的类都是从它继承来的
它提供了几个常用的方法
hashCode() //取对象的哈希值
wait() //用于线程通讯
notify() //用于线程通讯
notifyAll() //用于线程通讯
toString() //把对象转成字符串,直接打印对象的时候会自动调用这个方法
equals() //比较对另一个对象和“我”(调用equals()方的对象)是不是相等
finalize() //对象被垃圾回收器回收的时候会自动调用这个方法
clone() //克隆
getClass() //得到Class对象
public class Test5 {
public static void main(String[] args) {
Cat cat = new Cat(2,"TOM");
System.out.println(cat.toString()); //Cat [age=2, name=TOM]
}
}
class Cat{
int age;
String name;
public Cat(int age, String name) {
super();
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Cat [age=" + age + ", name=" + name + "]";
}
}
一个需要记住的知识点
public class Test4 {
public static void main(String [] args) {
int x1 = 2147483647+1;
System.out.println(x1); //-2147483648
long x2 = 2147483647+1;
System.out.println(x2); //-2147483648
long x3 = 2147483647+1L;
System.out.println(x3); //2147483648
}
}
5、抽象类
用abstract修饰的类
抽象方法:用abstract修饰,只有声明,没有实现,实现交给子类重写,含有抽象方法的类,必须声明为抽象类
抽象类的特点:
①用abstract修饰
②不能new出来,只能new它的子类,这个子类如果不能完全实现抽象类中的全部抽象方法,则它还是一个抽象类
③抽象类除了有抽象方法之外,其他的和普通类完全相同
④
比如
public class Test6 {
public static void main(String[] args) {
Bank bank = new ABCBank();
bank.save(); //银行存钱
bank.take(); //银行取钱
}
}
abstract class Bank{
abstract void save();
abstract void take();
}
class ABCBank extends Bank{
void save() {
System.out.println("银行存钱");
}
void take() {
System.out.println("银行取钱");
}
}
6、接口
接口可以理解为一种特殊的抽象类
如果抽象类中的所有的方法都是抽象的,可以用接口来代替
接口的特点:
①接口也不能new,要new它的实现类
②接口中所有的方法都是public 的
小常识:方法在子类中重写的时候,它的访问级别不能低于父类
public protected default private
public class TestInterface {
public static void main(String[] args) {
Bank bank = new ABCBank();
bank.save();
bank.take();
}
}
interface Bank{
void save();
void take();
}
class ABCBank implements Bank{
public void save() { //如果不加public就会报Cannot reduce the visibility of the inherited method
System.out.println("银行存钱");
}
public void take() {
System.out.println("银行取钱");
}
}
③接口可以继承接口,甚至可以多继承
interface A{
}
interface B{
}
interface C extends A,B{
}
④接口中的所有属性都相当于public static final 的,接口其实相当于抽象方法和常量的集合
public class TestInterface {
public static void main(String[] args) {
Bank.total();
}
}
interface Bank{
void save();
void take();
static void total() {
System.out.println("总额是....");
}
}
⑤jdk1.8 以后接口中可以有静态方法,默认方法(而且可以重写)
⑥一个类可以在继承一个类的同时,实现一或多个接口
⑦接口可以设计成空接口,JDK中就有这样的接口,称为标记接口,比如Serializeable Cloneable等
⑧接口可以声明在类内部作为内部接口,可以使用public private protected修饰,但能修饰外部接口的修饰符只有public
class T{
interface A{}; //可以使用public private protected修饰符
}
7、final关键字
用来修饰 类,属性,方法,局部变量,方法参数
(1)用final修饰的类不能被继承,jdk中就有这样的类,比如 tring System Math
(2)用final修饰的方法不能被重写
(3)用final修饰的属性在定义的同时就要初始化,如果不在定义的时候初始化则要在构造方法中初始化,如果有多个构造方法则要在每个构造方法中都进行初始化
(4)用final修饰的静态属性,必须在定义的同时进行初始化
(5)用final修饰的局部变量要在使用之前初始化
(6)用final修饰的引用,这个引用(地址)不能变但是引用指向的内容是可变的
public class TestFinal {
public static void main(String[] args) {
Sheep sheep = new Sheep();
test(sheep);
System.out.println(sheep.age); //1
}
static void test(final Sheep sheep) {
//sheep=null; //编译错误
sheep.age++;
}
}
class Sheep{
int age;
}
8、对象的比较
“==” 比的就是变量的字面量本身,比如
public class TestCompare {
public static void main(String[] args) {
Dog d1 = new Dog(2,"tom");
Dog d2 = new Dog(2,"tom");
System.out.println(d1==d2); //false
System.out.println(d1.equals(d2)); //false
}
}
class Dog{
int age;
String name;
public Dog(int age, String name) {
super();
this.age = age;
this.name = name;
}
}
对于上面的程序,因为我们没有重写equals方法,它是从Object类继承来的,所以比较的结果也是false,下面是Object类中equals的源码
public boolean equals(Object obj) {
return (this == obj);
}
如果想按照自己的想法实现对象的比较就要重写equals方法,比如
public class TestCompare {
public static void main(String[] args) {
Dog d1 = new Dog(2,"tom");
Dog d2 = new Dog(2,"tom");
System.out.println(d1==d2); //false
System.out.println(d1.equals(d2)); //true
}
}
class Dog{
int age;
String name;
public Dog(int age, String name) {
super();
this.age = age;
this.name = name;
}
public boolean equals(Object obj) {
if(this==obj)return true;
if(!(obj instanceof Dog))return false;
Dog dog = (Dog)obj;
if(this.age==dog.age&&this.name==dog.name)return true;
else return false;
}
}