对象

问一JAVA基础题,下面程序打出来结果是:AB,B
main调用operate(a,b)时,是对象引用的传递,传递a、b的地址给operate,在y=x的操作时,应该能改变b的值,为什么变量b的值没有发生改变呢?

    public class T{
        public static void main(String[] arg){
            StringBuffer a = new StringBuffer ("A");
            StringBuffer b = new StringBuffer ("B");
            operate (a,b);
            System.out.println(a + "," +b);
        }
        static void operate (StringBuffer x, StringBuffer y)  {
            x.append (y);
            y = x;
        }
    } 
  • *

局部变量和成员变量存在堆内存里还是栈内存里?

All local variables (including method arguments) –Stack(所有的局部变量都存在栈内存中)

Objects(including all their fields) –heap(所有的对象包括它们的成员变量都存在堆内存内)

reference在stack里 (引用类型存在栈内存中)

5.2.2方法的参数传递机制

  • 值传递

  • 对于基本类型的参数传递:

        public class PrimitiveTransferTest {
            public static void swap(int a,int b){
                int tmp=a;
                //int a=b;PrimitiveTransferTest.java:4: 错误: 已在方法 swap(int,int)中定义了变量 a
                //int b=tmp;
                a=b;
                b=tmp;
                System.out.println("swap方法结束后,a的值是:"+a+" ;b的值是:"+b);
            }
            public static void main (String[] args){
                int a=6;
                int b=9;
                swap(a,b);
                System.out.println("交换结束后,a的值是:"+a+" ;b的值是:"+b);
    
            }
        }  
    
  • 2.对于引用类型的参数传递:

            class DataWrap{
        int a;
        int b;
    
        }
    public class ReferenceTransferTest {
        public static void swap( DataWrap dw){
            //dw =new DataWrap(); 会发现a,b并没有被调换,因为在方法内新生成了一个DataWrap对象,因此传入的DataWrap会被覆盖掉。
            int dwt=dw.a;
            dw.a =dw.b;
            dw.b =dwt;
            System.out.println(dw.a+" "+dw.b);
        }
        public static void main(String[] args){
            DataWrap dw=new DataWrap();
            dw.a=6;
            dw.b=9;
            swap (dw);
            //this.swap(dw);错误:无法从静态上下文中引用非静态变量。
            System.out.println(dw.a+" "+dw.b);
    
        }
    
    }
    

5.2.4递归方法

  • 一个方法体内调用它自身,称为方法递归。

  • 例题:*已知有一个数列:f(0)=1,f(1)=4,f(n+2)=2*f(n+1)+f(n),求f(10)的值

  • public class Recursive {
    
        public static int fn(int n){
            if (n==0) { //不要少写一个等号!!!
                //fn(0)=1;错误: 意外的类型
                return 1;
            }
            else if (n==1) {
                return 4;
            }
            else {
                //int m=2*fn(n-1)+fn(n-2);
                //return m;
                return 2*fn(n-1)+fn(n-2);
            }
        }
        public static void main(String[] args){
            System.out.println(fn(10));
        }
    }
    

5.2.5方法重载

  • 如果一个类中包含了两个或两个以上方法的方法名相同,但形参列表不同,则被称为方法重载。java允许一个类里定义多个重名方法,只要形参列表不同就可以。
  • 和方法的返回值类型、修饰符等无关
    • 确定一个方法需要三个要素:
      • 调用者:方法的所属者,类或实例。
      • 方法名:
      • 形参列表:(定义该方法可以接受的参数,用参数类型 参数名表示,多参数之间用“,”隔开,一旦定义方法时指定了形参列表,则调用方法时必须传入对应的参数值)调用方法时,系统会根据传入的实参列表匹配目标方法。

5.3成员变量和局部变量

  • 成员变量指的是在类里定义的变量

  • 所有变量

    • 成员变量
      • 实例变量(不以static修饰)
      • 类变量(以static修饰)
    • 局部变量

      • 形参
      • 方法局部变量(在方法内定义)
      • 代码块局部变量(在代码块中定义)

        • 类变量从类的准备阶段起开始存在,直到系统完全销毁这个类,类变量的作用域和这个类的生存范围相同;
        • 而实例变量从该类的实例被创建时开始存在,直到系统完全销毁这个实例。
  • 访问成员变量:

    • 类.类变量
    • 对象.类变量
      • 注意java允许通过对象访问static修饰的成员变量本身就是一个错误,在底层上仍然是类来访问类变量。
    • 对象.实例变量

      class Person {
          public static int eyeNum;
          public String name;
      }
      public class TestPerson {
          public static void main(String[] args){
              System.out.println("Person中的eyeNum变量的值是"+Person.eyeNum);
              Person.eyeNum=2;
              System.out.println("Person中的eyeNum变量的值是"+Person.eyeNum);
              Person p = new Person();//不要将new写成大写的形式
              System.out.println(p.name);
              System.out.println("p对象中的name变量的值是"+p.name+"\np对象中的eyeNum变量的值是"+p.eyeNum);
              p.name="孙浩";
      
              System.out.println("p对象中的name变量的值是"+p.name+"\np对象中的eyeNum变量的值是"+p.eyeNum);
              Person p2=new Person();
              p2.name="李大钊";
              System.out.println("p2对象中的name变量的值是"+p2.name+"\np对象中eyeNum变量的值是"+p2.eyeNum);
      
          }
      }
      
    • 从上面程序可以看出,成员变量无需显式初始化,系统会为其默认初始化。

    • 局部变量除了形参之外,都必须显式初始化。
    • 形参的作用域是整个方法体内,且无需显示初始化,其初始化由系统完成。形参的值的由方法调用者负责指定。

      • 不过尽量避免这种情况发生。

        public class blockTest{
            public static void main(String[] args){
                {
                    //int a;  blockTest.java:5: 错误: 可能尚未初始化变量a
                    int a=3;
                    System.out.println("局部变量a的值是:"+a);
                }
                //System.out.println(a); blockTest.java:8: 错误: 找不到符号
            }
        }
        
      • 代码块局部变量离开所在的代码块后就立即被销毁

  • 注意一个类中不能定义两个重名的成员变量,即使一个是类变量,另一个是实例变量也不行;一个方法内不能出现两个同名的方法局部变量,注意方法局部变量与形参也不能同名;同一个方法体内不同的代码块局部变量可以同名。

  • java允许局部变量和成员变量同名,如果方法内的局部变量和成员变量同名,局部变量会覆盖成员变量;如果需要在方法中引用被覆盖的成员变量,需要this(对于实例变量)或类名(对于类变量)来调用。

    public class VariableOverrideTest{
        private String name="张三";
        private static double price=78.0;
        public static void main(String[] args){
            String name="孙悟空";
            int price=1;
            System.out.println(price);
            System.out.println(name);
            System.out.println(VariableOverrideTest.price);
            System.out.println(new VariableOverrideTest().name);
        } 
    }
    

5.4隐藏和封装

  • 将对象的成员变量和实现细节隐藏起来,不允许外部直接访问;
  • 把方法暴露出来,通过方法对这些成员变量进行安全的访问和操作;

5.4.1理解封装

5.4.2使用访问控制符

  • private 同一个类中
  • default 同一个类中;同一个包中
  • protected 同一个类中;同一个包中;子类中
  • public 同一份类中;同一个包中;子类中;全局范围内

  • 这个Person类实现了良好的封装:

    class Person {
        private String name;
        private int age;
        public void  setName( String name){
            if (name.length()>6||name.length()<2) {
                System.out.println("你输入的姓名格式有误");
                return;     
            }
            else {
                this.name=name;
            }
        }
        public String getName(){
            return this.name;
        }
    }
    public class PersonTest {
        public static void main(String[] args){
            Person p=new Person();
            p.setName("阿姆斯特丹戈尔巴乔夫");
            p.setName("Mike");
            //System.out.println(p.nama) 错误:name变量是private修饰的,不可以在别的类中直接对其访问。
            System.out.println(p.getName());
        }
    }
    
    • 这段代码中,main()方法不可直接修改Person对象的name和age两个实例变量,只能通过setter方法来操作这个实例变量的值。

    • 一个类常常就是一个小的模块,程序设计时,应该尽量避免一个模块直接操作和访问另一个模块的数据,模块设计追求高内聚和低耦合(仅暴露少量的方法给外部使用)

    • 如果一个java类的每个实例变量都被private修饰,并为每个实例变量都提供了public 修饰的setter方法和getter方法,那么这个类就是一个符号JavaBean规范的类。

  • 对于访问控制符的使用,有以下几条基本原则:

    • 类里绝大多数成员变量都应该使用private修饰;工具方法用于帮助实现该类的其它方法,这些方法也应该使用private修饰;
    • 如果某个类要用做其他类的父类,该类包含的大部分方法可能仅希望被子类重写,则应该使用protected修饰这些方法;
    • 希望暴露出来给其他类自由使用的方法应该用public修饰。
    • 外部类通常希望被其他类自由使用,所以大部分外部类使用public修饰。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值