zoukankan      html  css  js  c++  java
  • 构造方法,this,super,final,static

    1构造方法

    一个Person类,属性都被private了,外界无法直接访问属性,必须对外提供相应的set和get方法。但如果需要在创建对象的同时明确对象的属性值,就需要构造方法了。

    1.1定义

    构建创造时用的方法,即就是对象创建时要执行的方法

    格式:

      修饰符 构造方法名(参数列表)

      {

      }

     

    1.2特点

    1)构造方法没有返回值类型。也不需要写返回值。因为它是为构建对象的,对象创建完,方法就执行结束。

    2)构造方法没有具体的返回值。

    3)构造方法名称必须和类名保持一致。

     

    这就可以解释了,创建对象时,要加一个扩号,这不就是在调用方法嘛,

    Person p=new Person();

     

    例:

    public class Person {
    	private String name;
    	private int age;
    	
    	public Person(String name, int age) {
    		super();
    		this.name = name;
    		this.age = age;
    	}
    	
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}	
    }
    
    public class Test {
    	public static void main(String[] args) {		
    		Person p2=new Person("张三",18);
    		System.out.println(p2.getName());
    		System.out.println(p2.getAge());		
    	}
    }
    

    1.3内存图

     

    步骤解释:

    1 main方法进栈

    2在堆中开内存,赋初值

    3有参构造方法进栈

    4传参,赋值

    5有参构造弹栈

    6地址赋值给p2

    7 getname进栈,通过地址找到name,打印

    8 getage进栈,通过地址找到age,打印

    1.4默认构造方法

    编译器在编译java文件时,如果发现类中没有构造方法,会自动添加一个空参构造。

    但如果类中只要有一个构造方法,则不会自动添加空参构造了。

    如果写了有参构造方法,那么new对象时,再用空参的就会报错。

    所以如果写了有参构造,最好把空参构造也加上。因为使用空参构造的情况更多。有参构造用的比较少,一般测试时用。

    当描述的事物在创建其对象时就要明确属性的值,就用有参的

    若创建对象时不需要明确具体的数据,可以不用写构造方法,因为会自动加默认的空参构造方法。

    还是上面的例子,因为Person定义了有参,所以test再调用空参就会报错:

     

    1.5注意的细节

    1)一个类中可以有多个构造方法,(空参、部分成员变量是参数、全部成员变量都是参数)这其实是方法重载。

    2)构造方法可以被private修饰,这样其他程序无法创建该类的对象了。

    如果类比较重要,就可以这样,构造方法用private修饰,不让创建对象。

    其他方法可以用static修饰,那么就可以直接用类.方法,这样调用了。

    例如System类,就是这样的,

    eclipse中,在类上面,ctrl+点击该类,可以查看源码:

    1.6构造方法和一般方法区别

    构造方法在对象创建时就执行了,而且只执行一次。

    一般方法是在对象创建后,需要使用时才被对象调用,并可以被多次调用。

    对象在创建之后需要修改和访问相应的属性值时,在这时只能通过set..或者get..方法来操作。

    所以构造方法可以不写,get set必须写

    例:

    class Person {
    	void Person() {
    	}
    }
    
    class PersonDemo {
    	public static void main(String[] args) {
    		Person p = new Person();
    	}
    }
    

    这段代码的Person前面有返回值,所以不是构造方法,那么就会自动添加一个空参构造。所以代码是可以运行的,可以new对象的。但是不建议这样写,可以看到在eclipse中出现警告:

    2 this关键字

    之前用this可以解决成员变量和局部变量同名的问题。

    this代表的是对象,哪个对象调用了this所在的方法,this就代表哪个对象。

     

    this还可以用于在本类中构造方法之间的调用。

    2.1格式:

      this(参数列表); 

    注意:只能构造方法里用this(),普通方法里不能用this()。 

    例:

    public class Person {
    	private String name;
    	private int age;
    	
    	public Person(){
    //调用本类构造方法
    		this("李小华",19);		
    	}
    	
    	public Person(String name,int age){
    		this.name=name;
    		this.age=age;
    	}	
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public int getAge() {
    		return age;
    	}
    	public void setAge(int age) {
    		this.age = age;
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Person p1=new Person();		
    		System.out.println(p1.getName());
    		System.out.println(p1.getAge());
    		
    		Person p2=new Person("张小美",18);
    		System.out.println(p2.getName());
    		System.out.println(p2.getAge());
    	}	
    }
    

     

    这里的this("李小华",19);

    相当于:

    但是,this必须写在第一行,如果这样,是不行的

     

    原因是初始化动作要最先执行。

     

    2.2内存图

    步骤解释:

    1main进栈,看到new,堆中开内存,属性赋初值

    2空参进栈

    3找第一个参数是name,age的构造方法,进栈,并把参数传过去

    4赋值

    5有参构造弹栈,空参构造弹栈

    6地址赋给p

    7getName进栈,打印getAge进栈,打印

     

    例:判断两个人是否是同龄人

    (之前代码)

    3 super关键字

    3.1可以用于子父类中构造方法的调用

    例:

    public class Person {
    	public Person(){
    		System.out.println("这是父类构造方法");
    	}
    }
    
    public class Student extends Person{
    	public Student(){
    		System.out.println("这是子类构造方法");
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Student s=new Student();
    	}
    }
    

     

    为什么会这样呢?因为在创建子类对象时,父类的构造方法会先执行,

    子类中所有构造方法的第一行有默认的隐式super();语句。

    格式:

      调用本类中的构造方法

      this(实参列表);

      调用父类中的空参数构造方法

      super();

      调用父类中的有参数构造方法

      super(实参列表);

     

    3.2 但是,如果父类定义了有参构造,那么子类则必须调用super(参数),必须手动写上。

    因为父类不会自动创建空参构造了,所以子类的super()就找不到了。

    public class Person {
    	public Person(String name){	
    		System.out.println("这是父类构造方法");
    	}	
    }
    

     

    改成这样就可以了:

    所以一个类只要定义了有参构造,一定再写一个空参构造,因为有可能被继承,不写会导致子类报错。

    3.3为什么子类对象创建都要访问父类中的构造方法

    例:

    public class Person {
    	int a=1;	
    	public Person(String name){
    		a=5;
    		System.out.println("这是父类构造方法");
    	}	
    }
    
    public class Student extends Person{	
    	public Student(){
    		super("张三");
    		System.out.println("这是子类构造方法");		
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Student s=new Student();
    		System.out.println(s.a);
    	}
    }
    

     

    这里Student是Person的子类,因为Person中在构造方法改变了成员变量的值,所以如果Student不访问Person的构造方法,那么就得不到Person中真正的成员变量的值了,也就不是真的继承了。

    总结:

    子类会继承父类中的内容,所以子类在初始化时,必须先到父类中去执行父类的初始化动作。这样,才可以使用父类中的内容。 

    子父类是会一级一级的调用的,最终是object。

    3.4如果有this()

    如果子类的构造方法第一行写了this调用了本类其他构造方法,那么super调用父类的语句就没有了。因为this()或者super(),只能定义在构造方法的第一行,因为初始化动作要先执行。

    例:

    public class Animal {
    	public Animal(int age){		
    	}
    }
    

     

    这里写了this(),那么意思就是调用的下面的那个有参构造,而这里面有super,所以,上面就不能再写super了,会报错。

    3.5总结:

    1)如果有this();那么就不会有super();了。不写也不会自动加了。

    2)构造方法只要直接或间接可以调用父类构造方法就可以。

    3)this和super都是只能在构造方法中使用

    eclipse中也可以有构造方法的快捷方式:

    右键--source--Generate Constructor using Fields

    可以点任意个,一个不选,就是空参构造。

     

    可以看到,点出来后,第一行就是super();

    3.6 super练习

    描述学生和工人这两个类,将他们的共性name和age抽取出来存放在父类中,并提供相应的get和set方法,同时需要在创建学生和工人对象就必须明确姓名和年龄。

    public class Person {
    	private String name;
    	private int age;	
    	
    	public Person(String name, int age) {
    		super();
    		this.name = name;
    		this.age = age;
    	}
    	
    	public String getName() {
    		return name;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public int getAge() {
    		return age;
    	}
    	public void setAge(int age) {
    		this.age = age;
    	}	
    }
    
    public class Student extends Person{
    	public Student(String name, int age) {
    		super(name, age);		
    	}	
    }
    
    public class Worker extends Person{
    	public Worker(String name, int age) {
    		super(name, age);		
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Student s=new Student("小红帽",18);
    		System.out.println(s.getName());
    		System.out.println(s.getAge());
    		
    		Worker w=new Worker("大灰",81);
    		System.out.println(w.getName());
    		System.out.println(w.getAge());
    	}
    }
    

     

    super通常是这么用的,父类的构造方法既可以给自己的对象初始化,也可以给自己的子类对象初始化。

    总结:

    this的三个作用:

      解决成员变量和局部变量同名问题

      代表本类对象,调用本类中的变量和方法

      构造方法之间的调用

    super的两个作用:

      代表父类对象,调用父类的变量和方法

      子父类中构造方法的调用

    4 final关键字

    有些类在描述完之后,不想被继承,或者有些类中的部分方法功能是固定的,不想让子类重写。这时需要使用关键字final,final的意思为最终,不可变。final是个修饰符,可以用来修饰类,类的成员,以及局部变量。不能修饰构造方法

    4.1 final修饰类

    final修饰类不可以被继承,但是可以继承其他类(也叫太监类)

    例:

    public class Person {
    }
    
    public final class Father extends Person{
    }
    

     

    这里的father就不能被继承了。

    4.2 final修饰方法

    final修饰的方法不可以被子类重写,但父类中没有被final修饰方法,子类重写后可以加final。(也叫太监方法)

    例:

    public final class Father{
    	public final void method1(){		
    	}
    	public void method2(){		
    	}	
    }
    
    public class Son extends Father{	
    	public final void method2(){		
    	}
    }
    

    这里son可以重写method2,不能重写method1

     

    4.3 Final修饰局部变量

    1)局部变量是基本数据类型(称为常量):一旦赋值,终身不变

     

     

    2)局部变量是引用数据类型:一旦赋值一个地址,终身不变。但是地址内的对象属性值可以修改。

     

    4.4 Final修饰成员变量

    必须手动赋值或构造方法赋值。因为成员变量有默认值null,不赋值就终身是null了。

    只要在分配地址之前(也就是创建对象之前)赋值就可以。

    例:

     

    这样才可以:

     

    或这样:

    public class Person {
    	final String name2;	
    	public Person(String name2){
    		this.name2=name2;
    	}	
    }
    

    5 static关键字

    static修饰的成员变量属于类,不属于这个类的某个对象。

    static修饰后就共享了(有一个改变,就全变了)。

     

    5.1例:

    public class Student {
    	private String name;
    	private String schoolname;
    	
    	public Student() {
    		
    	}
    
    	public Student(String name, String schoolname) {		
    		this.name = name;
    		this.schoolname = schoolname;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public String getSchoolname() {
    		return schoolname;
    	}
    
    	public void setSchoolname(String schoolname) {
    		this.schoolname = schoolname;
    	}	
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Student s1=new Student("小红","清华大学");
    		Student s2=new Student("小明","清华大学");
    		Student s3=new Student("小亮","清华大学");
    		s2.setSchoolname("北京大学");
    		
    		System.out.println(s1.getSchoolname());
    		System.out.println(s2.getSchoolname());
    		System.out.println(s3.getSchoolname());
    	}
    }
    

     

    说明schoolname是属于每一个对象的

    改:private static String schoolname;

     

    这时schoolname是共享的了,是属于Student类的了。

    5.2内存图

     

    (数据共享区也叫 静态区)

    内存图步骤说明:

    1 test.class进共享区,扫描到main,student.class,也进入

    2因为main是static,所以main进静态区

    3扫描student.class,有static的schoolname,就进静态区,并赋值初始值null

    4 main方法进栈

    5 有new,就在堆中开内存,找到属性 name赋值null(这时不会再找schoolname了,因为已经在静态区了)

    6 分配地址

    7 构造方法进栈,传值:小红,清华大学

    8 this.name,找到地址,然后找到name,赋值小红

    9 根据地址去静态区找schoolname(这里应该用类.变量才对,但是用对象.变量还是能找到的)静态区的schoolname被改值为清华大学

    10构造方法弹栈

    11 地址赋值给s1

    12 s2的new,s3的new,过程是一样的...

    13 执行到s2.setSchoolname("北京大学")这一步时,静态区schoolname被改成北京大学

    14 后面System.out.println访问的就全是北京大学了

    5.3 Static特点

    1)属于类,不属于对象

    如果一个对象将static成员变量值进行了修改,其他对象的也跟着变,就是共享一个。

    2)通过类名直接调用,不建议用对象调用(会有警告)

     

    这样就可以:

     

    5.4注意的地方

    1)不能用this和super调用(因为this代表本类对象,super代表父类对象,但是被static后已经不属于对象了)

    2)静态内容是优先于对象存在,只能访问静态

    3)同一个类中,静态成员只能访问静态成员,不能访问非静态

    简单记:

    非静态可以调静态

    静态不能调非静态

      

    因为static是进共享区的,所以可以理解为先有static show2,后有age,所以在show2中找不到age。

    这也解释了,一个类中有main方法时,其他方法必须加static,才可以调用。

     

     

    这里的methods();其实写全了,是Test.methods();

    如果方法不加static,就得new一个test对象,来调用(因为对象能调用变量和方法)

     

    5.5特殊的地方

    1)main方法是特殊的,main方法为静态方法仅仅为程序执行入口,它不属于任何一个对象,可以定义在任意类中。main是虚拟机调用。

    2)多态中也有特殊:

    多态调用方法中,编译看左边,父类有,编译成功,父类没有,编译失败

    运行静态方法,运行父类中的静态方法,

    运行非静态方法,运行子类的重写方法(因为静态了,就属于类了)

    成员变量,编译运行全是父类

    例:

    public class Father {
    	static int i=1;
    	public static void f(){
    		System.out.println("这是父类静态方法");
    	}
    }
    
    public class Son extends Father{
    	static int i=2;
    	public static void f(){
    		System.out.println("这是子类重写后的静态方法");
    	}
    }
    
    public class Test {
    	public static void main(String[] args) {
    		Father f=new Son();
    		System.out.println(f.i);
    		f.f();
    	}
    }
    

    5.6定义静态常量

    静态常量一旦赋值,终身不变。可以类.变量名调用。

    5.6.1定义格式:

      public static final 数据类型 变量 = ;

      (这里不一定非要Public,也可以私有,但是没意义,所以都是public)

    5.6.2规则

    static写final前面,

    变量名全部大写,多个单词使用下划线连接。

    例:public static final String SCHOOL_NAME = "北京大学";

    Math.PI也是静态常量

    5.6.3接口中的每个成员变量都默认使用 public static final 修饰。

    所有接口中的成员变量已是静态常量,由于接口没有构造方法,所以必须显示赋值。可以直接用接口名访问。(因为用final定义的成员变量必须赋值)

  • 相关阅读:
    NTP时钟服务器(卫星授时)技术让网络时间同步不再难
    视频监控系统为何需要GPS北斗授时服务器?
    如何选购GPS北斗卫星时钟同步装置?市场均价多少?
    Orange'S学习笔记(一)
    Oracle 11g中文版高清视频教程
    新书推荐:Orange'S:一个操作系统的实现
    引导扇区汇编代码解释
    灰度图转伪彩色图代码
    Visual Odometry For GPSDenied Flight And Mapping Using A Kinect
    [原创]日行一善,命运在不知不觉中改变
  • 原文地址:https://www.cnblogs.com/hzhjxx/p/10060558.html
Copyright © 2011-2022 走看看