封装

在描述对象时候,例如描述对象为狗,可以设置Dog.age= 100;看上去语法没有任何毛病,但是显然这么写是不合理的。因此,java提供了封装的机制,将类和对象的成员变量进行封装。

案例1:

class FengZhuang
{
    publicstatic void main(String[] args){
        Dogjinmao = new Dog();
        jinmao.setAge(180);
        //jinmao.age= 100;
    }
}
class Dog
{
    private int age;
    public void setAge(intage){
        if(age > 20){
            System.out.println("滚犊子!");
            return;
        }
        System.out.println("设置成功");
        this.age = age;
    }
}
 


概念:

封装是面向对象三大特征之一,它指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,而是通过该类提供的方法来实现对内部信息的访问。这样,当我们设置属性值的时候,可以判断设置的属性值是否合理。

//TODO
private int age;
    publicvoid setAge(int age){
        if(age> 20){
            System.out.println("滚犊子!");
            return;
        }
        System.out.println("设置成功");
        this.age= age;
    }
 


封装是面向对象编程语言对客观世界的模拟,在客观世界里,对象的信息都是被隐藏在对象内部,外界无法直接操作访问和修改。就如对Dog.age设置属性那样,外界不能直接修改age属性,只能随着岁月的流逝(条件),age才会增加。

封装的目的:

1、  隐藏类的实现细节。

隐藏和封装的区别:

隐藏就是将属性私有化(private),不能被外界直接访问。

封装比隐藏多一步,另外提供公有的方法让外界去操作该隐藏属性。

如下:temp是内部实现功能的细节,只需要隐藏。而age是描述对象属性,需要隐藏起来后提供公有方法对其进行访问和设置。

class Dog
{
         //这个变量的业务逻辑只是在该对象方法中有一个记录
         //临时数据功能
         privateString temp;
         privateint age;
         publicvoid setAge(int age){
                   temp= "这个狗狗的年纪是"+age;
                   if(age> 20){
                            System.out.println("滚犊子!");
                            return;
                   }
                   System.out.println("设置成功");
                   this.age= age;
         }
         publicint getAge(){
         System.out.println(temp);
                   returnage;
         }
}


2、让使用者只能通过预定义的方法来访问数据,从而可以在该方法中添加控制逻辑,限制对成员变量的不合理的访问。

3、可进行数据检查,从而有利于保证对象完整性。

4、提高代码的可维护性。

为了实现良好的封装,需要从两个方面考虑:

1、将对象的成员变量和实现细节隐藏起来,不允许外部直接访问。

2、将方法暴露出来,让方法来控制对这些成员变量进行安全访问和操作。

因此封装实际上就是:将该隐藏的隐藏,将该暴露的暴露。而实现这一目的则是通过java提供的访问控制符来实现。

 

访问控制符(权限修饰符)

java提供3个访问控制符关键字,private、protected、public分别代表三个访问控制级别,另外还有一个默认访问控制级别,一共4个访问控制级别。

默认访问控制即不写权限修饰符(default)。

控制级别由小到大排序为:

private->default->protected->public

使用4种权限类型控制的效果:

private:修饰的成员(变量、方法、构造器)只能在当前类内部访问,外界是无法获取该成员。显然,使用这个修饰符可以达到隐藏成员变量的目的。

class FengZhuang
{
    public static void main(String[] args){
        Dog jinmao = new Dog();
        jinmao.age = 100;
    }
}
class Dog
{
    private int age;
 
}


default:默认修饰符,不适用任何修饰符关键字修饰。修饰的成员或类可以被相同包下的其他类访问,不能被其他包下的类访问。

案例:定义bao1. Bao1Class, bao1. Bao1Class2, bao2. Bao2Class,在bao2下的Bao2Class类无法访问在bao1下的Bao1Class的name属性。但是,bao1下的Bao1Class2类可以访问在bao1下的Bao1Class的name属性。

package bao1;
public class Bao1Class{
    staticString name;
}
 
package bao2;
import bao1.*;
public class Bao2Class{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}
 
package bao1;
public class Bao1Class2{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}


protected:子类访问权限修饰符,修饰的成员可以被同包、不同包下的子类访问。通常使用该修饰符修饰的方法,希望其子类能重写这个方法。

package bao1;
public class Bao1Class{
    staticprotected String name;
}
Bao2Class不可以访问Bao1Class的name属性
package bao2;
import bao1.*;
class Bao2Class {
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}
package bao1;
public class Bao1Class{
    staticprotected String name;
}
Bao2Class可以访问Bao1Class的name属性,因为有继承关系
package bao2;
import bao1.*;
class Bao2Class extends Bao1Class {
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}


public:公开访问权限,这是最宽松的访问权限级别,修饰的成员、类,那么这个成员或者外部类可以被所有包下所有类访问。

权限最大,在任意位置,都可以访问(注意:导包)


 

修饰符修饰类:

注意:外部类只能用public 或者默认权限修饰,不能使用private、protected来修饰。

因为被这两个修饰的类不能被访问,也就没有任何意义。

//TODO代码验证权限修饰符

测试public修饰的类:

package bao1;
public class Bao1Class{
    staticpublic  String name;
}
 
package bao2;
import bao1.*;
class Bao2Class{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}
 
默认修饰符(default):
package bao1;
class Bao1Class{
    staticpublic  String name;
}


这样是无法访问的,因为Bao1Class权限仅限bao1包下,bao2中的类无法访问。

package bao2;
import bao1.*;
class Bao2Class extends Bao1Class{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}


这样是可以访问的,因为Bao1Class2和Bao1Class在一个包下。

package bao1;
class Bao1Class2{
    publicstatic void main(String[] args){
        Bao1Class.name= "小明";
    }
}


不能使用private和protected修饰类


总结已学的修饰符。

static:静态修饰符;

private:私有权限修饰符;

default:默认权限修饰符;

protected:子类权限修饰符;

public:公开的权限修饰符。

 

当使用private修饰构造器的时候,会出现什么情况?

Private修饰的方法,作用范围是:类本身,其他类不能调用。

 

那么将对象的构造器方法都私有后,就无法创建对象了,那么在实际应用中,还可以通过暴露一个公开的方法,让外界获取一个对象。

 

    classDuoTai
    {
        publicstatic void main(String[] args){
            Personperson = Person.getPerson();
            person.method();
        }
    }
    classPerson
    {
        privatePerson(){
            System.out.println("构造器方法执行");
        }
        publicstatic Person getPerson(){
            returnnew Person();
        }
        public  void method(){
            System.out.println("执行person中的方法");
        }
    }
 


单例设计模式

这种案例在实际开发中,我们以单例模式举例。

当我们上网时候,发现顾客是多个,但是服务生是一个,并不是一个顾客有一个服务生。

那在这个时候,网管就是唯一的,那网管就是单例对象。

 

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

·        1、单例类只能有一个实例。

·        2、单例类必须自己创建自己的唯一实例。

·        3、单例类必须给所有其他对象提供这一实例。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决:一个全局使用的对象频繁地创建与销毁。

何时使用:当您想控制实例数目,节省系统资源的时候。

如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码:构造函数是私有的。

更多相关资料请查阅:http://www.runoob.com/design-pattern/singleton-pattern.html

代码实现:

class Singleton
{
    publicstatic  void main(String[] args){
        /*显然,这种情况不符合常理
            实际中,一个网管,服务多个顾客,
            网管就是唯一的,我们把网管对象变为唯一
            对象,就符合常理了。
        */
        Customerc1 = new Customer();
        c1.surfing();
        Customerc2 = new Customer();
        c2.surfing();
        Customerc3 = new Customer();
        c2.surfing();
    }
}
class Customer
{
    publicvoid surfing(){
        Waiterwaiter = Waiter.getWaiter();
        waiter.kaiji();
    }
}
class Waiter
{
    privateWaiter(){
   
    }
    privatestatic  Waiter waiter;
    publicstatic Waiter getWaiter(){
        //这个时候,我要保证每次获取网管对象都是唯一的
        if(waiter== null){
            waiter= new Waiter();
            returnwaiter;
        }
        returnwaiter; 
    }
    int temp =0;
    publicvoid kaiji(){
        System.out.println("开机" + temp +"号电脑");
        temp++;
    }
}
 


接下来介绍单例模式的两种实现方式:

1、  懒汉式,顾名思义,获取单例对象的操作采用偷懒的方式。

在代码中,那就是说:你什么时候需要用到该对象,那么什么时候再创建。

如下代码:当调用getWaiter方法获取对象时,才会创建对象。而不调用getWaiter方法的话,是不会创建对象的。

 

class Waiter
{
    private Waiter(){
   
    }
    privatestatic  Waiter waiter;
    publicstatic Waiter getWaiter(){
        //这个时候,我要保证每次获取网管对象都是唯一的
        if(waiter== null){
            waiter= new Waiter();
            returnwaiter;
        }
        returnwaiter; 
    }
    int temp =0;
    publicvoid kaiji(){
        System.out.println("开机" + temp +"号电脑");
        temp++;
    }
}
 

2、  饿汉式

和懒汉式相反,在类存在的时候,该类型对象就存在了!即便你没有调用getWaiter方法,该对象也存在!

class Waiter
{
    privateWaiter(){   }
    privatestatic  Waiter waiter = new Waiter();
    publicstatic Waiter getWaiter(){
        /*这个时候,不管有没有调用该方法,
        返回的对象就已经存在了!而且该对象
            属于类,所以每次调用该方法,返回
            的就是唯一的Waiter*/
        returnwaiter; 
    }
    int temp =0;
    publicvoid kaiji(){
        System.out.println("开机" + temp +"号电脑");
        temp++;
    }
}
 


其实这两种单例模式在开发中也并不是非常完美,但是作为现阶段,我们只需熟练编写上面两个案例即可,如果还有兴趣,可以参考下面链接的文章,还有其他创建单例对象的方式(按住ctrl键单击)。

http://www.runoob.com/design-pattern/singleton-pattern.html

 

 

 

 

 

思考案例:

情况1:

定义Person类,定义Man类,两个类不在同一个包下

package bao1;
public class Person{
    protectedint age;
}
 
import bao1.Person;
public class Man
{
    Person p = new Person();
    publicvoid setAge(){
        p.age= 12;
    }
}


编译Man类会报错,因为age属性是protected修饰,必须是Person本包下或它的子类才可以访问,这里Man即不在同一个包下,也不是Person子类!

情况2:

定义Person类,定义Man类,两个类不在同一个包下

package bao1;
public class Person{
    protectedint age;
}


 

 

 

 

import bao1.Person;
public class Man extends Person
{
    Person p = new Person();
    publicvoid setAge(){
        p.age= 12;
    }
}


这种情况还是会报错,因为虽然Man继承了Person,但是,实际上访问age属性的还是Person对象,这里并不满足Man类和Person类在同一包下,也不满足调用age属性的对象是Person对象的子类。这里的p指的是Person类型对象,不是他的子类对象。

情况3:

正确的情况:

定义Person类,定义Man类,两个类不在同一个包下

package bao1;
public class Person{
    protectedint age;
}
 


 

 

 

import bao1.Person;
public class Man extends Person
{
    Man p =new Man();
    publicvoid setAge(){
        p.age= 12;
    }
}


 

这里,p.age是可以的,虽然Man不和Person在同一个包下,但是,创建出来访问age属性的对象是Person类型对象的子类对象,符合protected权限修饰符的访问范围,所以不报错!

 

情况4:

编写测试类TestPro,测试并思考:

package bao1;
public class Person{
    protectedint age;
}


 

import bao1.Person;
public class Man extends Person
{
    public intgetAge(){
        returnthis.age;
    }
    publicvoid setAge(int age){
        this.age= age;
    }
}


 

 

class TestPro{
    publicstatic void main(String[] args){
        Manman = new Man();   
        man.setAge(123);
        intage = man.getAge();
        System.out.println(age);
    }
}


 

这里通过测试类创建man对象,然后调用Man对象的age属性。

在man对象中,this代表的是当前对象,这个当前对象又是Person类的子类对象,所以是可以访问protected修饰的age属性,所以不会报错!!

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值