第五章,面向对象基础篇

5.3 封装性
  • 为了解决属性必须封装且又必须访问的矛盾,只要是被封装的属性,必须通过setter和getter方法设置和取得。
  • 为前面类的私有属性加上getter和setter方法

Public void setAge(int a){
  Age = a;
}
Public int getAge(){
  Return age;
}

setter方法可以加上检测代码检测输入的数据是否合法。


5.4构造方法
  

Person per = null;声明对象时不调用构造方法。
Per = new Person();实例化对象时调用构造方法。

• 构造方法也是可以重载的。只要每个构造方法的参数类型或参数个数不同,即可实现重载。


5.5 匿名对象
匿名对象只在堆内存中开辟空间,而不在栈内存的引用。

new Person("cathy",30).tell(); //匿名对象

 

5.6 实例讲解

class Student{
  private String stuno;
  public Student(){
    public Student(String stuno){
      this.setStuno(stuno);
    }
  }
  public float sum(){
    return math+english;
  }
  public float avg(){
    return this.sum/3;
  }

5.7 String
• ==是用来进行地址比较的
Str2 str3指向同一个空间,他们的地址值就是相同的。
内容比较用equals,

str2.equals(str3)
“hello”.equals("hello"),一个字符串可以调用string类中的方法,说明一个字符串就是一个string类的匿名对象。

 

• String str1 = “hello”;

使用这种方式定义字符串有一个好处,就是如果一个字符串已经被一个名称所引用,则以后再有相同的字符串声明时,就不会再重新开辟空间。

String str2 = “hello”; str2==str1.
java中有个字符串池。这种设计叫共享设计,设计思路是,对象池中保存多个对象,新实例化的对象如果已经在池中定义了,则不再重新定义,指向已存在的实例空间。
使用new关键字,无论如何都会重新开一个空间。
对于字符串,就直接赋值,不要采用new。


• 字符串的内容一旦声明不可改变。
非要改变就用stringbuffer类。

 

• String (char[] value)字符数组变字符串。这是一个构造方法
char[] toCharArray() 字符串变字符数组。这是一个普通方法
char charAt(int index)字符串中取出指定位置字符
int length()字符串长度
String trim() 清除左右两端空格
String[] split(String regex) 按指定字符串拆分 

IO操作中经常会遇到字符串与byte数组或char数组之间的转换操作。

• length取得数组的长度。
length()取得字符串的长度。

 

5.8 引用传递及基本应用

  1.引用传递

public class RefDemo02{
    public static void main(String args[]){
        String str1 = "hello" ;            // 实例化字符串对象
        System.out.println("fun()方法调用之前:" + str1) ;
        fun(str1) ;                        // 调用fun()方法
        System.out.println("fun()方法调用之后:" + str1) ;
    }
    public static void fun(String str2){        // 此处的方法由主方法直接调用
        str2 = "MLDN" ;                    // 修改字符串内容
    }
};

 程序运行结果

fun()方法调用之前:hello
fun()方法调用之后:hello

因为字符串的内容一旦声明是不可改变的,改变的只是其内存地址的指向。

class Demo{
    String temp = "hello" ;        // 此处为了方便,属性暂时不封装
};
public class RefDemo03{
    public static void main(String args[]){
        Demo d1 = new Demo() ;    // 实例化Demo对象,实例化之后里面的temp=30 
        d1.temp = "world" ;        // 修改temp属性的内容
        System.out.println("fun()方法调用之前:" + d1.temp) ;
        fun(d1) ;
        System.out.println("fun()方法调用之后:" + d1.temp) ;
    }
    public static void fun(Demo d2){        // 此处的方法由主方法直接调用
        d2.temp = "MLDN";                        // 修改temp值
    }
};

 

  2.接收本类的引用

class Demo{                        // 定义Demo类
    private int temp  = 30 ;    // 声明temp属性并封装
    public void fun(Demo d2){    // 接收本类的引用
        d2.temp = 50 ;            // 直接通过对象调用本类的私有属性
    }
    public int getTemp(){        // getter
        return temp ;
    }
    public void setTemp(int t){    // setter
        temp = t ;
    }
};
public class RefDemo04{
    public static void main(String args[]){
        Demo d1 = new Demo() ;    // 实例化Demo对象
        d1.setTemp(50) ;        // 只能通过setter方法修改内容
        d1.fun(d1) ;            // 此处把Demo的对象传回到自己的类中
        System.out.println("temp = " + d1.getTemp()) ;
    }
};

 

  3.person类中可以有一个书属性,这个属性可以是book类。book类中可以有主人属性,这个属性可以是person类

class Person{            // 定义Person类
    private String name ;    // 姓名
    private int age ;        // 年龄
    private Book book ;        // 一个人有一本书
   private Person child; //一个人一个孩子,person类有一个属性,值是另一个person类。
public Person(String name,int age){ this.setName(name) ; this.setAge(age) ; } public void setName(String n){ name = n ; } public void setAge(int a){ age = a ; } public String getName(){ return name ; } public int getAge(){ return age ; } public void setBook(Book b){ book = b ; } public Book getBook(){ return book ; } }; class Book{ // 定义Book类 private String title ; // 标题 private float price ; // 价格 private Person person ; // 一本书属于一个人 public Book(String title,float price){ this.setTitle(title) ; this.setPrice(price) ; } public void setTitle(String t){ title = t ; } public void setPrice(float p){ price = p ; } public String getTitle(){ return title ; } public float getPrice(){ return price ; } public void setPerson(Person p){ person = p ; } public Person getPerson(){ return person ; } }; public class RefDemo05{ public static void main(String arg[]){ Person per = new Person("张三",30) ; Book bk = new Book("JAVA SE核心开发",90.0f) ; per.setBook(bk) ; // 设置两个对象间的关系,一个人有一本书 bk.setPerson(per) ; // 设置两个对象间的关系,一本书属于一个人
    
System.out.println("从人找到书 --> 姓名:" + per.getName()+";年龄:" + per.getAge() +";书名:" + per.getBook().getTitle() + ";价格:" + per.getBook().getPrice()) ; // 可以通过人找到书 System.out.println("从书找到人 --> 书名:" + bk.getTitle() + ";价格:" + bk.getPrice() + ";姓名:" + bk.getPerson().getName() + ";年龄:" + bk.getPerson().getAge()) ; // 也可以通过书找到其所有人 } };

 

    

5.9 this 关键字

    1.可以使用this强调本类中的方法

  2.表示类中的属性

public Person(String name){
  name=name;
}
Vs.
public Person(String name){
  This.name=name;
}

3.调用本类的构造方法

如果一个类中有多个构造方法,可以利用this关键字互相调用。

  

public Person(){
    System.out.println("一个新的Person对象被实例化。")
}
public Person(String name, int age){
    this();
    this.name = name;
}          

 

使用this调用构造方法必须也只能放在构造方法的第一行。

this调用构造方法是一定要留一个构造方法作为出口,即程序中至少存在一个构造方法不使用this调用其他构造方法。

一般都将无参构造方法作为出口。

    4.表示当前对象

      

class Person{
    public Person(){
        pass
    }  
    public boolean compare(Person per){
        Person p1 = this;
        Person p2 = per;
        //person对象中有一个方法compare,可以用传进来的per对象和当前对象作对比
    }
}        

 

 5.10 static 关键字

  1.java中常用的内存区域

    • 栈内存空间:保存所有的对象名称(更准确的说是保存了引用的堆内存空间的地址)
    • 堆内存空间:保存了每个对象的具体属性内容
    • 全局数据区:保存static类型的属性
    • 全局代码区:保存所有的方法定义

  2.类属性调用

    类名称.static属性

    Person.country = "b city" 

  3.使用static声明方法

public static String getCountry(){
    return country;
}

4.使用static属性统计一个类产生了多少个实例化对象

5.使用static为对象进行自动的编名操作

6.程序中的System.exit(1)表示系统退出,只要在exit()方法中设置一个非零的数字,则系统执行到此语句之后将退出系统。

7.如果一个方法要由主方法直接调用,则必须按以下格式声明:“punlic static 方法的返回值类型,方法名称(参数列表){}”。因为主方法是静态方法,而静态方法是不能调用非静态方法的,所以之前的方法声明处才必须加上static关键字。

 

5.11 代码块

  1.普通代码块

  2.构造块

    构造块是直接写在类中的代码块,构造块优先于构造方法执行,每次实例化对象都会执行构造块中的代码。

class Demo{
    {
        System.out.println("定义构造块");
    }
    public Demo(){
        System.out.println("构造方法");
    }
}    

   3.静态代码块

    使用static声明的代码块。静态代码块优先于主方法执行,而在类中定义的静态代码块会优先于构造块执行,而且不管有多少个对象产生,静态代码块只执行一次。

class Demo{
    static{
        System.out.println("静态代码块");
    }
}

    静态代码块的妙用:静态代码块优先于主方法执行,那么就可以直接使用静态代码块而不使用主方法向屏幕上打印hello world了。成功打印hello world后,会爆找不到主方法的异常。解决办法是,在程序输出完hello world之后直接让程序退出即可。

5.12 构造方法私有化

  1.对构造方法进行封装

    

class Singleton{
    private Singleton(){
    }//此处将构造方法进行封装
}
public class SingleDemo02{
    public static void main(String args[]){
        Singleton s1 = null; //可以声明对象
        s1 = new Singleton();//错误,无法实例化
    }
}

   解决方法

class Singleton{
    //在内部产生本类的实例化对象,将属性封装
    private static Singleton instance = new Singleton();
    private Singleton(){ //将构造方法封装
    }
    public static Singleton getInstance(){ //通过静态方法取得Singleton类的实例
        return instance;
    }
}

 

public class demo{
  public static void main(String args[]){
    Singleton s1 = Singleton.getInstance();
    
Singleton s2 = Singleton.getInstance();   
  }
}

 instance,s1,s2 都指向同一个堆内存,不管有多少个对象,实际上只有一个实例。

在设计模式中将这样的设计成为单例设计模式,及无论程序怎样运行,Singleton类永远只会有一个实例化对象存在。


5.13 对象数组  
  1.对象数组的声明
    类 对象数组名称[] = new 类[数组长度];
Person per[] = new Person[3];
per[0] = new Person("cathy");
per[1] = new Person(“tom”); 
//分别为数组中的每个元素初始化,每一个都是对象,都需要单独实例化。

 


//声明一个对象数组,里面有三个对象,使用静态初始化方式
Person per[] = {new Person("张三"),new Person("李四"),new Person("王五")};

 5.14 内部类

  1.使用static定义内部类

    用static定义的内部类变成了外部类,用static声明的内部类不能访问非static的外部类属性。(在实际应用中用的不多,但是不代表没有价值。http://bbs.csdn.net/topics/350021609)

    内部类的第一个好处就体现出来了——隐藏你不想让别人知道的操作,也即封装性。
    内部类的第二个好处——一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!   

  2.在外部访问内部类

    外部类.内部类 内部类对象 = 外部类.new 内部类();    
    Outer.Inner in = out.new Inner();
     

  3.在方法中定义内部类

      在方法中定义的内部类不能直接访问方法中的参数,如果方法中的参数想要被内部类所访问,参数钱必须加上final关键字。

      

class Outer{        // 定义外部类
    private String info = "hello world" ;    // 定义外部类的私有属性
    public void fun(final int temp){        // 定义外部类的方法
        class Inner{                        // 在方法中定义的内部类
            public void print(){                // 定义内部类的方法
                System.out.println("类中的属性:" + info) ;        // 直接访问外部类的私有属性
                System.out.println("方法中的参数:" + temp) ;
            }
        };
        new Inner().print() ;                // 通过内部类的实例化对象调用方法
    }
};
public class InnerClassDemo05{
    public static void main(String args[]){
        new Outer().fun(30) ;    // 调用外部类的方法
    }
};

实例

  如果觉得分析类有困难,可以先把基本功能做完,做完之后对一些输入的数据进行验证,再把主方法中的代码尽可能减少,然后再去考虑代码的可重用性。

本章要点

  如果一个对象没有被实例化而直接使用,则使用时会出现空指向异常。

  类属于引用数据类型。进行引用传递时,传递的是堆内存的使用权。

  使用构造方法实例化string时产生两个实例化对象,其中一个是垃圾空间。

  如果需要限制类对象的产生可以将构造方法私有化。一旦将构造方法私有化,在类的外部就不能new新对象,只能在类的内部创建好一个对象然后调用这个对象。这样就限制了对象的产生。

  对象数组的使用要分为声明数组和为数组开辟空间两步。开辟空间后数组中的每个元素的内容都是null。

  在方法中声明的内部类要想访问方法的参数,则参数前必须加上final关键字。因为方法的变量属于局部变量,离开该方法,变量就失去了作用,也就会自动被消除,内部类却不会离开所在方法是就失去作用。

 
posted @ 2017-11-09 09:58  cathy_mu  阅读(292)  评论(0编辑  收藏  举报