变量及其传递 & 内部类

一、 Java变量及其传递

1.1 基本数据变量与引用型变量

1. ?Java变量:
(1). 基本型变量(8种)
   char,byte,short,int,long,float,double,boolean
(2). 引用型变量:对象,接口,数组

java 两个变量接收函数_java 两个变量接收函数


java 两个变量接收函数_内部类_02

举例:
    public class MyDate{
	private int day=12;
	private int month=6;
	private int year=1900;
	public MyDate(int y,int m,int d){
		year=y;
		month=m;
		day=d;}
          void addYear()
	{   year++;}
         public void display(){
	System.out.println(year+"-"+month
             +"-"+day);
	}

    public static void main(String[] args){
       MyDate m,n;
       m=new MyDate(2003,9,22);
       n=m;     "//n和m指向同一个地址"
       n.addYear();
       m.display();
       n.display();
       System.out.println(m.toString());
       System.out.println(n.toString());	
    }
    }
      /*运行结果
       2004-9-22
       2004-9-22
       MyDate@11a698a
       MyDate@11a698a
      */


1.2 成员变量与局部变量

成员变量与局部变量有没有区别?
成员变量若为static的称为类变量,否则称为成员变量,而局部变量是在方法体内的变量。
(1) ?从语法形式上看,成员变量是属于类或接口的,而局部变量是在方法中定义的变量或方法的参变量;
成员变量可以被public,private,static等修饰,而局部变量则不能被访问控制符及static修饰;成员
变量及局部变量都可以被final修饰。
(2) ?从变量在内存中的存储方式看,成员变量是对象的一部分,而对象是存在于堆中的,而局部变量是
存在于栈中的。
(3) ?从变量在内存中的存在时间上看,成员变量是对象的一部分,它随着对象的创建而存在,而局部变
量随着方法的调用而产生,随着方法调用结束而自动消失。
(4) ?成员变量如果没有赋初值,则会自动以该类型的默认值(0,false,null等)赋值;而局部变量则不会
自动赋值,必须显示地赋值后才能使用。

class A{
         int a;
         void m(){
            int b;
            System.out.println(a);  //合法的,a的值为0
            System.out.println(b);  //不合法,编译不通过
           }
        }


1.3 变量的传递

1. ?按值传递:当将一个参数传递给一个函数时,函数接收的是原始值的一个副本。因此,如果函数修改了该参数,仅改变副本,而原始值保持不变。(传递8种基本型变量)
2. ?按引用传递:当将一个参数传递给一个函数时,函数接收的原始值的内存地址,而不是值的副本,因此,如果修改了该参数,调用代码中的原始值也随之改变。(传递对象,接口,数组)
Java中的参数传递比C++简单,按值传递所有参数,制作所有参数的副本,而不管它们的类型。

例1:
class TestTransOfValue
{
  public static void main(String args[])
  {
    int val;
    StringBuffer sb1, sb2;
    val = 10;
    sb1 = new StringBuffer("apples");
    sb2 = new StringBuffer("pears");
    System.out.println("val is " + val);
    System.out.println("sb1 is " + sb1);
    System.out.println("sb2 is " + sb2);
    System.out.println("");

System.out.println("calling modify");
    //按值传递所有参数
    modify(val, sb1, sb2);
    System.out.println("returned from modify");
    System.out.println("");
    System.out.println("val is " + val);
    System.out.println("sb1 is " + sb1);
    System.out.println("sb2 is " + sb2);
  }

public static void modify(int a, StringBuffer r1,
                         StringBuffer r2)
  {
    System.out.println("in modify...");
    //在方法中修改基本类型变量的值
    a = 0;  
    //在方法中修改对象引用值的副本
    r1 = null;  //1
    //在方法中修改副本的对象实体值
    r2.append(" taste good");
    System.out.println("a is " + a);
    System.out.println("r1 is " + r1);
    System.out.println("r2 is " + r2);
  }
}
运行后输出:
val is 10
sb1 is apples
sb2 is pears
calling modify in modify...
a is 0
r1 is null
r2 is pears taste good 
returned from modify
val is 10
sb1 is apples
sb2 is pears taste good 
/*关于这里的sb1和r1:
当参数传到modify后,r1和sb1指向同一个地址,若改变了r1指向的地址,并不会更改sb1指向的地址。这个时候就
相当于看作两个指针了。
关于sb2和r2:
sb2和r2指向同一个地址,这个地址指向的值(实体值)被改变了,则结束后sb2和r2的实体值也就相应的改变了。
*/

java 两个变量接收函数_java 两个变量接收函数_03

例2:
class Swap
{ 
 public static void main(String args[])
  {
    Integer a, b;
    a = new Integer(10);
    b = new Integer(50);
    System.out.println("before swap...");
    System.out.println("a is " + a);
    System.out.println("b is " + b);
    swap(a, b);
    System.out.println("after swap...");
    System.out.println("a is " + a);
    System.out.println("b is " + b);
}

 public static void swap(Integer a, Integer b)
  {
    Integer temp = a;
    a = b;
    b = temp;
    System.out.println("in swap...");
    System.out.println("a is " + a);
    System.out.println("b is " + b);
  }
}
/*
运行后输出:
before swap...
a is 10
b is 50
in swap…
a is 50
b is 10
after swap...
a is 10
b is 50 
*/

参数传递总结:
(1) Java按值传递所有参数,制作所有参数的副本,而不管它们的类型
(2) 对于基本类型的变量形参修改了并不能反映到函数外面的实参
(3) 对于引用类型的变量,在形参中修改了对象实体值可以反映到实参,在形参中修改了对象引用值,
不能反映到实参


1.4 引用型变量的实体值、引用值比较

1. ?参数传递总结:
(1) 比较基本类型的数据: 和!=
(2) 如果要比较引用型变量是否相同,可以直接用
和!=吗? 答:不能

==和!=用来比较引用型变量时(只能比较引用值(地址)是不是相等),只能判断运算符两边引用的是不是同一个对象,即对象的地址值(或对象引用值)!!!!!
如何比较两个对象的内容(对象实体值)是否相同?
用equls()方法:

2. ?引用型变量比较总结:
(1) 比较两个变量是否同一个对象(即对象引用值是否相同),用==和!=
(2) 比较两个变量的内容是否相同用equals方法
(3) 自己定义的类如果要支持equals方法必须重写从Object类继承来的equals方法(比如前面的String类
是java自己的类就不需要重写equals,但是Employee类就是自己定义的类则需要重写equals)

Object类中的equals方法:
public boolean equals(Object obj){
return (this==obj);
}

equals示例1:
class EqualsTest{
  public static void main(String[] arguments)
  {
     String str1,str2;
     str1="Free the bound periodicals.";
     str2=str1;
     System.out.println("String1: "+str1);
     System.out.println("String2: "+str2);
     System.out.println("Same object? "+(str1==str2));      //true
     str2=new String(str1);
     System.out.println("String1: "+str1);
     System.out.println("String2: "+str2);
     System.out.println("Same object? "+(str1==str2));      //false
     System.out.println("Same value? "+str1.equals(str2));  //true
     String str3,str4;
     str3="busy";
     str4="busy"; //str4=new String("busy")或str4=new String(str3) 
     System.out.println("String3: "+str3);
     System.out.println("String4: "+str4);
     System.out.println("Same object? "+(str3==str4));       //true
     System.out.println("Same value? "+str3.equals(str4));   //true 
     String str5,str6;
     str5="str5busy";
     str6="str6busy";
     System.out.println("String5: "+str5);
     System.out.println("String6: "+str6);
     System.out.println("Same object? "+(str5==str6));      //false
     System.out.println("Same value? "+str5.equals(str6));  //false 	
   }
}
equals示例2:
import java.util.*;
public class EqualsTest {
     public EqualsTest() {    }    
     public static void main(String[] args){
     Employee alice1=new Employee("Alice",75000,1987,12,15);
     Employee alice2=alice1;
     Employee alice3=new Employee("Alice",75000,1987,12,15);
     Employee bob=new Employee("Bob",50000,1989,10,1);
     System.out.println("alice1==alice2: "+(alice1==alice2));    //true
     System.out.println("alice1==alice3: "+(alice1==alice3));    //false 
     System.out.println("alice1.equals(alice3): "+alice1.equals(alice3));  //true
     System.out.println("alice1.equals(bob): "+alice1.equals(bob));   //false 
     System.out.println("bob.toString(): "+bob);  
  }
}

class Employee{
    private String name;
    private double salary;
    private Date hireDay; 
    public Employee(String n,double s,int year,int month,int day){
            name=n;
            salary=s
        hireDay=new Date(year,month,day);
    }
    public String getName(){     return name;     }
    public double getSalary(){   return salary;    }
    public Date getHireDay(){   return hireDay; }
    public void raiseSalary(double byPercent){
            double raise=salary*byPercent/100;
            salary+=raise;
 }

public boolean equals(Object otherObject){     //子类覆盖了Object的equals方法
  if(this==otherObject) return true;
  if(otherObject==null) return false;
  if(getClass()!=otherObject.getClass())
  return false;
  Employee other=(Employee)otherObject;
  return name.equals(other.name)&&
              salary==other.salary&&hireDay.equals(other.hireDay); 
                        //子类覆盖了Object的toString方法
 }
 public String toString(){
  return getClass().getName()+
           "[name="+name+",salary="+salary+",hireDay="+hireDay+"]";
 }
 private String name;
 private double salary;
 private Date hireDay;
}


二、 内部类

2.1 内部类的定义与使用

1. ?内部类的定义:将类的定义置入一个用于封装它的类(外部类)里。
注意:
内部类不能与外部类同名(否则,编译器无法区分内部类与外部类),如果内部类还有内部类,内部类的内部类不能与它的任何一层外部类同名。
作用:
逻辑分组, 隐藏细节

/*内部类结合多态可以很方便的隐藏类的细节(包括类名)
*/
interface Contents{
  int value();
}
interface Destination {
  String readLabel();
}
class Goods{
    private class Content implements Contents{  //"private class Contentimplements Contents" 
        private int i=11;
        public int value(){
  return i;
    }
  }
    protected class GDestination    //"protected class GDestination implements Destination"
    implements Destination{
      private String label;
  private GDestination(String whereTo){
    label=whereTo;
  }
public String readLabel(){
    return label;}}
public Contents cont(){
  return new Content();
  }
public Destination dest(String s){
  return new GDestination(s);
  }
  }
public class TestGoods {   //"public class TestGoods"
    public static void main(String[] args){
         Goods g=new Goods();
         Contents c=g.cont();
         Destination d=g.dest("Beijing");
    }
}

2. ?内部类对象的创建:创建非静态内部类的对象时一定要确保已经有一个外部类对象。
(1) 利用外部类的方法创建并返回,因为方法是由外部类对象调用的,那创建该内部类对象时,一定已经拥有了所属的外部类对象了
public Contents cont(){      Goods g=new Goods();
return new Content();       Contents c=g.cont();
}

(2) 创建内部类还可以在除外部类中的其它类中,但是要确保该类具有访问内部类的权限,并且已经创建了一个外部类对象。格式如下:

outerObject=new outerClass(Constructor Parameters);
outerClass.innerClass innerObject = outerObject.new InnerClass(Constructor Parameters);

 Goods g1=new Goods();
 Goods.Content c1=g.new Content(); 
OR
 Goods g1=new Goods();
 Goods.GDestination d1=g1.new GDestionation();


3. ?内部类的修饰符:
(1)public、protected、private和缺省:访问权限修饰符,用来限定内部类的访问权限,
  一般的外部类是不能用protected和private修饰的。访问权限修饰符的限定和成员变量的限定一样。
(2)final:表明内部类不能继承。
(3)abstract:抽象内部类,不能被实例化。
(4)static:表明一个静态内部类。

4. ?静态内部类:
和普通的非静态内部类有较大的不同,使用时要遵循如下原则:
(1)实例化static内部类时,在new前面不需要用对象变量;
(2)static内部类中不能访问其外部类的非static属性及方法,即只能访问static成员;
(3)static方法中不能访问非static的属性及方法,也不能不带前缀地new一个非static的内部类。

class A
{
      private int x;
      void m(){
  new B();
     }

     static void sm(){
      //在外部类的静态方法中
     //不能直接创建内部类对象
     //new B();//!!error
    }
class B
{
      B(){x=5;}
  }//B类结束
}//A类结束
class Outer
{
  static class Inner
  {
  }
}

class TestInnerStatic
{
  public static void main(String[] args)  
  {
    //创建非静态内部类B的对象a_b和ab
    A.B a_b=new A().new B();
    A a=new A();
    A.B ab=a.new B();
    
    //创建静态内部类Inner的对象oi,不需要外部类Outer的对象
    Outer.Inner oi=new Outer.Inner();
    //Outer.Inner oi2=Outer.new Inner();//!!error
    //Outer.Inner oi3=new Outer().new Inner();//!!error
  }
}


5. ?内部类中访问外部类的成员:
(1) 内部类中是可以直接访问外部类的其他属性与方法的,即使它们是private的。
(2) 如果内部类中有与外部类同名的属性与方法,可以使用下面的格式来表达外部类的引用,从而区分外部类和内部类的同名的属性与方法:
outerClass.this


2.2 方法和作用域中的内部类

内部类也可以是局部的,它可以定义在一个方法甚至一个代码块之内。
(1) 内部类中是可以直接访问外部类的其他属性与方法的,即使它们是private的。
(2) 如果内部类中有与外部类同名的属性与方法,可以使用下面的格式来表达外部类的引用,从而区分外部类和内部类的同名的属性与方法:
outerClass.this

例1: 方法中的内部类:
interface Destination {
  String readLabel();
}

public class Goods2 {
  String a="Goods2";
     public Destination dest(String s) {
          class GDestination implements Destination {
            private String label;
            private GDestination(String whereTo) {
             label = whereTo;
             System.out.println("access outer class:"+a);
               }
               public String readLabel() { return label; }
          }
          return new GDestination(s);
     }
public static void main(String[] args) {
          Goods2 g= new Goods2();
          Destination d = g.dest("Beijing");
          }
}
/*在方法dest()中定义了一个内部类,最后由这个方法返回这个内部类的对象。如果在用一个内部类的时候仅需要创建它的一个对象并传给外部,就可以这样做。
*/


方法中定义内部类的注意点:
(1) 方法中定义的类,在其它地方使用时,没有类的名字,一般用其父类来引用这样的变量。
(2) 同局部变量一样,方法中的内部类前面不能用public,private,protected修饰,也不能用static修饰,但可以被final或abstract修饰。
(3) 方法中的内部类,可以访问其外部类的成员;若是static方法中的内部类,可以访问外部类的static成员。
(4) 方法中的内部类中,不能访问该方法的局部变量,除非是final的局部变量。

例2: 作用域中的内部类:
public class Goods3{
     private void internalTracking(boolean b) {
          if(b) {
               class TrackingSlip {
                    private String id;
                    TrackingSlip(String s) {
                         id = s;
                    }
                    String getSlip() { return id; }
               }
              TrackingSlip ts = new TrackingSlip("slip");
               String s = ts.getSlip();
          } 
     }
 public void track() { internalTracking(true); }
     public static void main(String[] args) {
          Goods3 g= new Goods3();
          g.track();
     }
}


2.3 匿名内部类

匿名类: 类或方法中定义的一种没有类名的特殊内部类。
作用:当需要创建一个类的对象而且用不上它的名字时,使用内部类可以使代码看上去简洁清楚。
语法规则如下:
new interfacename(){……};
或new superclassname(){……};

注意:
(1) 这种类不取名字,而直接用其父类的名字或者它所实现的接口的名字;
(2) 类的定义与创建该类的一个对象同时进行,即类的定义前面有一个new,没有类的首部,对象的创建和类体共同构成一个匿名类表达式,后面以“;”结束;
(3) 类中不能定义构造方法,因为它没有名字。

interface Contents{
  int value();
}
public class Goods4 {
     public Contents cont(){
          //返回匿名类对象,该匿名类继承了Contents接口
          return new Contents(){
               private int i = 11;
               public int value() { 
                    return i; 
               }
          };
     }
 public static void main(String[] args)
     {
      Goods4 g=new Goods4();
      Contents c=g.cont();
     }
}