6.4 根父类
1、如何理解根父类是object这句话?
(1)所有类都直接或间接的继承Object(字面解释)
(2)Object类型的变量,可以接收任意类型的对象
(3)Object类型的数组,可以任意类型的元素
(4)规定Object[]类型的数组,可以接收任意的对象数组
(5)规定Object[]类型的数组,不可以接收元素是基本数据类型的一维数组
(6)Object类的所有方法(一共11个),在任意类型的对象中都可以找到。
public class Demo {
}
public class TestObject {
public static void main(String[] args) {
Object obj1 = "hello";
Object obj2 = 1;//这里1是Integer的对象
Object obj3 = new Scanner(System.in);
Object[] arr1 = new String[5];
Object[] arr2 = new Date[5];
// Object[] arr3 = new int[5];//错误,int不是引用数据类型
TestObject t = new TestObject();
t.method("hello");
t.method(1);
t.method(new Scanner(System.in));
String[] strings = new String[5];
t.fun(strings);
int[] nums = new int[5];
// t.fun(nums);//错误,因为Object[] arr形参只能接收对象数组,不能接收基本数据类型的数组
Demo d = new Demo();
System.out.println(d.toString());//从Object类继承的
System.out.println(d.getClass());//从Object类继承的
}
public void method(Object obj){
//.....
}
public void fun(Object[] arr){
///...
}
/*public void fun(int[] arr){
///...
}
public void fun(double[] arr){
}*/
}
6.5 构造器
6.5.1 构造器的作用和特点
成员:
(1)成员变量(*****)
(2)成员方法(*****)
(3)构造器(*****)
(4)代码块(**)
(5)成员内部类(**)
1、什么是构造器?它的作用是什么?
构造器的作用是创建对象,并且为对象的实例变量初始化。
2、构造器的特点
(1)构造器的名字必须和类名完全一致,包括大小写。
(2)构造器没有返回值类型,一旦写了返回值类型,它就变成普通方法了。
(3)构造器的修饰符只允许有public,protected,缺省,private四个之一
(4)所有类都有构造器,
如果没有编写构造器,编译器会给你自动加一个默认的无参构造。这里默认的意思是,权限修饰符和class前面默认一致。
(5)程序员也可以手动编写构造器,
一旦我们编写了构造器,编译器就不再给你添加默认的无参构造了。
(6)构造器可以重载,一个类可以有多个构造器。
(7)当声明子类时,在子类的构造器中,默认会调用父类的无参构造。
如果父类没有无参构造,又没有手动调用父类的有参构造,那么编译报错。
结论:
要么让它默认调用父类的无参构造, 不写
要么必须手动调用父类的有参构造, super(实参列表);
当然也可以手动调用父类的无参构造。 super();
super(); 或 super(实参列表); 必须在子类构造器的首行。
建议大家:父类尽量保留无参构造。
public class Employee {
private String name;
private double salary;
private int age;
//如何快速声明构造器呢?快捷键是Alt + Insert
public Employee() {
}
public Employee(String name, double salary, int age) {
this.name = name;
this.salary = salary;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
", age=" + age +
'}';
}
}
public class Manager extends Employee {
private double bonus;
public Manager() {
//super();
}
public Manager(String name, double salary, int age, double bonus) {
super(name, salary, age);
this.bonus = bonus;
}
}
public class TestEmployee {
public static void main(String[] args) {
/*Employee e1 = new Employee();//无参构造
Employee e2 = new Employee("张三",18000,23);
System.out.println(e1);
System.out.println(e2);
e2.setAge(24);//可以修改对象的属性
System.out.println(e2);*/
}
}
public class TestManager {
public static void main(String[] args) {
Manager manager = new Manager();//调用Manager类的无参构造创建对象
}
}
6.5.2 调用当前类的其他构造器
3、同一个类中,构造器是否可以互相调用?
可以
调用形式:
(1)this();
(2)this(实参列表);
这两句代码和super(); 或 super(实参列表);一样,必须在构造器的首行。
最终结论:
子类构造器首行如果没有写: this(); this(实参列表); super(); 或 super(实参列表);,默认就是super();
如果手动写了它们中的任意一种,写谁就是谁。
public class Goods {
private String title;//标题,名称
private double price;//价格
private double amount;//数量
private boolean reback;//是否支持退货
public Goods() {
super();
}
public Goods(String title, double price) {
this();
this.title = title;
this.price = price;
}
public Goods(String title, double price, double amount, boolean reback) {
/*this.title = title;
this.price = price;*/
this(title, price);
this.amount = amount;
this.reback = reback;
}
}
6.5.3 自动生成构造器
4、IDEA生成构造器的快捷键
(1)Alt + Insert,选择Constructor
(2)自定义快捷模板,用于生成无参构造
6.6 非静态代码块
类的成员:
(1)成员变量
(2)构造器(又叫构造方法)
(3)代码块(了解)
(4)成员方法
(5)内部类
1、代码块有两种形式:
(1)静态代码块
(2)非静态代码块
2、非静态代码块的作用
配合构造器在创建对象时,完成对象实例变量的初始化过程。
3、它的语法结构:
【修饰符】 class 类名{
{
非静态代码块
}
}
4、执行特点
非静态代码块是在构造器调用时自动调用的。每new对象,就会执行一次非静态代码块。
先于构造器的代码执行。
5、需求:
(1)所有的构造器在new对象之前,都输出一句话:一个对象被创建了
(2)给a,b变量赋值,用随机数[0,100)值赋值
解决方案有两种:
(1)把构造器的公共代码放到非静态代码块中
(2)把公共代码放到某一个构造器里面(通常是无参构造)然后其他构造器通过this(); 或 this(实参列表);调用这个代码
public class Demo {
public Demo(){
System.out.println("Demo.Demo");
}
{
System.out.println("非静态代码块");
}
}
public class TestDemo {
public static void main(String[] args) {
Demo d1 = new Demo();
Demo d2 = new Demo();
}
}
public class MyClass {
private int a;
private int b;
private String info;
{
System.out.println("一个对象被创建了");
a = (int)(Math.random()*100);
b = (int)(Math.random()*100);
}
public MyClass(){
}
public MyClass( String info) {
this.info = info;
}
@Override
public String toString() {
return "MyClass{" +
"a=" + a +
", b=" + b +
", info='" + info + '\'' +
'}';
}
}
6.7 实例初始化过程(面试题)
1、实例初始化过程:就是给对象的实例变量赋值的过程
2、刚才讲了3个操作都可以给实例变量赋初始值
(1)声明实例变量时,直接=值
(2)非静态代码块
(3)构造器
实际开发中都是选择构造器这一种方式比较多。
如果这3种方式同时存在,或者其中2种同时存在,那么实例变量的值最后以谁为准呢。
这就要求我们弄清楚它们的执行顺序,后面的会把前面的赋值给覆盖了。
3、实例初始化过程的顺序
(1)super();或super(实参列表);
(2)声明实例变量时,直接=值
(3)非静态代码块
(4)构造器其他代码(除了super();或super(实参列表);)
(1)最先执行的,然后(2)和(3)是按照代码编写的顺序执行,(4)在它们后面
4、编译器会把上面的4个部分的代码,组装成一个一个的<init>实例初始化方法。
你编写了你几个构造器,就有几个<init>实例初始化方法。
组装的顺序就是按照上面的(1),然后(2)和(3)是按照代码编写的顺序组装,(4)在它们后面。
init:initialize初始化
public class Demo {
public Demo(int a) {
this.a = a;
}
private int a = 1;
{
a = 2;
}
public Demo() {
}
@Override
public String toString() {
return "Demo{" +
"a=" + a +
'}';
}
}
public class Father {
{
System.out.println("父类的非静态代码块");
}
public Father(){
System.out.println("Father.Father");
}
}
public class Son extends Father {
{
System.out.println("子类的非静态代码块");
}
public Son(){
super();
System.out.println("Son.Son");
}
}
public class TestSon {
public static void main(String[] args) {
Father f = new Son();
}
}
6.8 关键字整理
6.8.1 this和super
1、this代表什么意思?
当前对象
2、如何理解当前对象?
(1)构造器、非静态代码块中出现,this代表你正在new的这个对象
(2)方法体中出现,this代表调用方法的对象
3、this使用的形式
(1)this独立使用,可以用于输出等
(2)this()或this(实参列表)
表示调用当前类的其他构造器,而且必须在构造器的首行。
this():调用当前类的无参构造。
this(实参列表):调用当前类的有参构造。
(3)this.成员变量
A:当局部变量(通常是形参)与成员变量重名时,使用this.成员变量与局部变量进行区分。
B:没有重名问题,也可以使用this.成员变量,表示访问成员变量。
思考?this.成员变量是否一定是当前类声明的?
通常 this.成员变量指当前类声明的,但是它也可以是父类声明的。
要通过this.成员变量访问父类声明的成员变量,有条件:
A:父类声明的成员变量的权限修饰符,必须是在子类仍然可见 >private。
B:子类不能有和父类重名的成员变量
(4)this.成员方法
完全可以省略this.,加或不加this.都一样。
如果是this.后面是虚方法的话:
编译时:this.成员方法表示先从当前类查找匹配的方法,如果没有找到,继续从父类声明的方法列表中寻找匹配的方法。
运行时:要看this的运行时类型,如果this代表子类的对象,要看子类是否重写了该方法。
this:编译时类型,当前类类型,
运行时类型,要看new的对象类型。
4、super的意思:代表父类声明的xx。
super引用任何父类的成员,都要求该成员在子类是可见的。
5、super的使用形式
(1)super()或super(实参列表)
表示匹配父类的无参构造或有参构造,必须在子类构造器的首行。
实际执行的是父类的<init>()或<init>(形参列表)的实例初始化方法。
(2)super.成员变量
当子类有和父类重名的成员变量,那么super.成员变量代表父类的,this.成员变量代表子类的。
this.成员变量先从当前类的成员变量列表开始找,如果找到,就是子类的,如果没找到,就去父类找。
super.成员变量,就是直接从父类成员变量列表找。
(3)super.成员方法
当子类重写了父类的方法时,要调用父类被重写方法,就用super.成员方法,
否则不需要用super.就可以直接调用从父类继承的方法。
6、总结
(1)构造器访问
super()或super(实参列表):一定代表父类的构造器,而且仅限于直接父类。
this()或this(实参列表):一定代表当前类的构造器,不会去别的类找。
(2)成员变量访问
this.成员变量:从当前类的成员变量列表开始找,如果找到,就是子类的,如果没找到,就去父类找。
super.成员变量:直接从父类成员变量列表找。
(3)方法调用
super.方法:一定从父类的成员方法列表找,找到谁就执行谁。
this.方法:
如果是虚方法,
编译时:this.成员方法表示先从当前类查找匹配的方法,如果没有找到,继续从父类声明的方法列表中寻找匹配的方法。
运行时:要看this的运行时类型(new),如果this代表子类的对象,要看子类是否重写了该方法。
(4)this可以独立使用,super不允许独立使用。
6.8.2 native
1、native:本地的
2、native在Java中是一个修饰符,只能用来修饰方法。
3、用native修饰的方法,表示本地方法,它在.java文件中没有方法体。
【修饰符】 class Java类{
【其他修饰符】 native 返回值类型 方法名(【形参列表】);
}
它的方法体在底层C或C++中。
4、Object类中
public native int hashCode(); 返回对象的哈希值
public final native Class<?> getClass(); 返回对象的运行时类型
5、在Java中如何使用native修饰的方法呢?
完全不用管native的事,直接调用即可。
甚至子类也可以重写native修饰的方法。
6.8.3 final
1、final:最终的,不可更改的
2、final的用法:
(1)修饰类,即在class前面加final
表示这个类不能被继承,比喻太监类,断子绝孙类
我们见过的String,Math,System类。
往往final修饰的类都非常重要,它里面的所有方法都不允许重写,不允许扩展。
(2)修饰方法,即在方法的返回值类型前面加final
表示这个方法不能被子类重写,可以被子类继承。
(3)修饰变量,即在变量的数据类型前面加final
表示这个变量的值不能修改,是常量
final修饰的变量必须手动初始化,
A:形参:靠实参初始化
B:其他局部变量,必须手动赋值
C:成员变量,必须在非静态代码块、构造器、成员变量声明后面给它初始值
final修饰的成员变量没有set方法,在Java层面它是无法修改值的。
建议,final修饰的变量用大写。
public class Triangle {
private final double a;
private final double b ;
private final double c ;
public Triangle(double a, double b, double c) {
if(a>0 && b>0 && c>0 && a+b>c && a+c>b && b+c>a) {
this.a = a;
this.b = b;
this.c = c;
}else{
this.a = 0;
this.b = 0;
this.c = 0;
}
}
public double getA() {
return a;
}
public double getB() {
return b;
}
public double getC() {
return c;
}
@Override
public String toString() {
return "Triangle{" +
"a=" + a +
", b=" + b +
", c=" + c +
'}';
}
}
public class TestFinal {
public static void main(String[] args) {
final int a = 1;
// a = 2;//错误,final修饰的变量是常量,不能修改
Triangle t = new Triangle(3,4,5);
System.out.println(t);
}
}
/*
final class Demo{
}
class SubDemo extends Demo{//报错,不允许继承final修饰的类
}*/
class MyClass{
public final void method(){
System.out.println("MyClass.method");
}
}
class SubClass extends MyClass{
//报错,不能重写final方法
/* public final void method(){
System.out.println("MyClass.method");
}*/
}
标签:Java,变量,笔记,class,学习,构造,父类,super,public
From: https://blog.51cto.com/u_16213911/7065886