Java 封装

什么是封装?

   封装:

         装:把属性装载
        封:私有化,提供访问权限

在面向对象程式设计方法中,封装(英语:Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。

封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问。

要访问该类的代码和数据,必须通过严格的接口控制。

封装最主要的功能在于我们能修改自己的实现代码,而不用修改那些调用我们代码的程序片段。

适当的封装可以让程式码更容易理解与维护,也加强了程式码的安全性。

封装的优点:

  • 良好的封装能够减少耦合。
  • 类内部的结构可以自由修改。
  • 可以对成员变量进行更精确的控制。
  • 隐藏信息,实现细节。

怎么进行封装?

第一步:属性私有化(使用private关键字进行修饰属性)

第二步:对外提供简单的操作入口

第二步详解:

1个属性对外提供一个set方法和一个get方法。外部程序只能通过set方法修改属性,只能通过get方法读取属性。(可以在set方法设立关卡来保证数据的安全性)

注意:set和get方法都是实例方法,不能带static。

               不带static的方法称为实例方法(就是之前的非静态方法),实例方法的调用必须先new对象(用引用.方法名的方式)

set和get方法的书写规范:

        set:

        public void set +属性 名首字母大写(1个参数){

                xxx=1个参数;

        }

        get:

        public 返回值类型   get+属性名首字母大写(无参){

                return  xxx;

         }

代码示例:

public class Person {

  //非私有化属性
  String address;

   //私有化属性
  private int age;
  private String name;

  //提供对外访问的方法setter和getter
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;//(在这里表示本类的引用,
                        // 用来区分成员变量和局部变量同名的冲突问题)
                        // this关键字在下篇文章单独讲解
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
         = name;
    }
}

非私有化属性的访问和修改:

public class Test02 {
    public static void main(String[] args) {
        Person p= new Person();
        //读取非私有化属性
        String address = p.address;
        System.out.println(address);

        System.out.println(p.address);
        //修改非有化属性
        p.address="三东";
        System.out.println(p.address);
    }
}
结果:null
     null
     三东

私有化属性的读取和修改:

public class Test02 {
    public static void main(String[] args) {
        Person p= new Person();
        ="sss";//编译错误
    }
}
public class Test02 {
    public static void main(String[] args) {
        Person p= new Person();
        //读取私有化属性
        int age = p.getAge();
        String name = p.getName();
        System.out.print(age+" ");
        System.out.print(name+" ");

        System.out.print(p.getAge()+" ");
        System.out.println(p.getName()+" ");

        //修改私有化属性
        p.setAge(10);
        p.setName("张三");
        System.out.print(p.getAge()+" ");
        System.out.println(p.getName()+" ");
    }
}
结果:0 null 0 null 
     10 张三

注意:set和get方法只是两个普通的实例方法,名字是可以任意的,但是一般我们都是要满足set和get方法的书写规范。如以下例子:

但是访问权限一定不能是private.

public class Person {
    //私有化属性
  private int age;
    public void age(int  age){
        this.age=age;
    }
    public int s(){
        return age;
    }
}
public class Test02 {
    public static void main(String[] args) {
        Person p = new Person();
        p.age(10);
        System.out.println(p.s());
    }
}
结果:10

Java继承:

继承:属性继承(代码,空间的继承,数据的拷贝)
           方法继承(访问权限)

在不考虑多态的情况,静态也会被继承和可以重写

什么是继承?

继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。

Java继承是面向对象的最显著的一个特征。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。 

类和类之间的继承关系可以用UML符号表示,其中父类又叫超类基类,子类又叫派生类。父类是子类的一般化,子类是父类的特化(具体化)。

继承的优点:

1.易维护性

java中继承可以通过增强一致性来减少模块间的接口和界面,可以增加了程序的易维护性。

2.复用性

java中继承可以提供程序的复用功能,可以减小代码和数据的冗余度,增加程序的重用性。

3.调理性

java中继承可以简化代码的复杂程度,能清晰体现相关类间的层次结构关系,使用代码的调理更加清晰。

继承的特性:

  • Java中规定,子类继承父类,除了构造方法不能继承之外,剩下的都可以继承。但是私有属性无法在子类中直接访问。
  • 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
  • 子类可以用自己的方式实现父类的方法。
  • Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 B 类继承 A 类,C 类继承 B 类,所以按照关系就是 B 类是 C 类的父类,A 类是 B 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
  • 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。

继承关键字:

继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。

1.extends关键字

在 Java 中,类的继承是单一继承,也就是说,一个子类只能拥有一个父类,所以 extends 只能继承一个类。

2.implements关键字

使用 implements 关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。

代码示例:

extends

//父类
public class Person {
    //非私有化属性
    String gender;
    //私有化属性
    private int a=10;
    //普通方法
    public void see() {
        System.out.println("看世界");
    }
    //get方法
    public int getA(){
        return a;
    }
}
//子类
 class Man extends Person{

 }
public class Test02 {
    public static void main(String[] args) {
        Man man = new Man();
        //对非私有属性的继承
        man.gender="男";
        //对see方法的继承
        man.see();
        //对get方法的继承,和对私有化属性的继承
        System.out.println(man.getA());

        System.out.println(man.gender);
    }
}
结果:看世界
      10 男

implements(此处不详细讲接口,只看继承(实现)的形式就可)

public interface Animal {
    void eat();
}

interface 生命{
    void run();
}

class Dog implements Animal,生命{

    @Override
    public void eat() {
        System.out.println("吃饭");
    }

    @Override
    public void run() {
        System.out.println("快跑");
    }
}
public class Test03 {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();
        dog.run();
    }
}
结果:吃饭
     快跑

方法的重写(覆盖):

        

方法的重写规则:

首先两个类必须有继承关系

  • 参数列表与被重写方法的参数列表必须完全相同
  • 返回类型与被重写方法的返回类型可以不相同,但是必须是父类返回值的派生类(java5 及更早版本返回类型要一样,java7 及更高版本可以不同)。
  • 访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为 public,那么在子类中重写该方法就不能声明为 protected。
  • 父类的成员方法只能被它的子类重写。
  • 声明为 final 的方法不能被重写。
  • 声明为 static 的方法不能被重写,但是能够被再次声明。
  • 子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为 private 和 final 的方法。
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 public 和 protected 的非 final 方法。
  • 重写的方法能够抛出任何非强制异常,无论被重写的方法是否抛出异常。但是,重写的方法不能抛出新的强制性异常,或者比被重写方法声明的更广泛的强制性异常,反之则可以。
  • 构造方法不能被重写。
  • 如果不能继承一个类,则不能重写该类的方法

方法覆盖注意事项:

1,方法覆盖只针对方法,和属性无关。

2,私有方法无法覆盖

3,构造方法不能被覆盖(因为不能被继承)

4,方法覆盖只针对实例方法,静态方法覆盖没有意义

toString()方法:

toString ()方法是Java.lang包下的Object类的方法,而Object类是所有Java类的父类(所有类都继承了Object类)。也就是说每个类都有toString()方法。

1,toString ()方法有什么作用?

它是将”Java对象“转换成”字符串的形式“。

2,Object类中的toString ()方法的默认实现是什么?

public String toString(){

return getClass().getName() + "@"  +Integer.toHexString(hashcode());

}

这就是调用了Object中的toString()方法 ,这显然是达不到我们要求的(无法直观的看到我们所创建的对象,只能看到一串地址字符),所有我们一般会对Object中的toString()方法 进行重写。

public class Address {
    String city;
}
class Test08{
    public static void main(String[] args) {
        Address address= new Address();
        System.out.println(address.toString());
        System.out.println(address);
    }
}
结果:task02.Address@1540e19d
      task02.Address@1540e19d

 重写过后:

1,

public class Address {
    String city;

    public String toString() {
        return "city:"+city;
    }
}
class Test08{
    public static void main(String[] args) {
        Address address= new Address();
        System.out.println(address);
    }
}
结果:city:null

2.一般使用这种(看起来跟清晰)

public class Address {
    String city;

    @Override
    public String toString() {
        return "Address{" +
                "city='" + city + '\'' +
                '}';
    }
}
class Test08{
    public static void main(String[] args) {
        Address address= new Address();
        System.out.println(address.toString());
        System.out.println(address);
        System.out.println(address.city);
    }
}
结果:Address{city='null'}
    Address{city='null'}
    null

toString()方法是怎么被调用的呢?

让我们看下面的例子:
当我么要想看address时,想让程序员直观的看到,肯定是要转换成字符或字符串的。而toString()方法就是为了这个目的而出现的。

当你使用"System.out.println(address)"语句时,其实会自动在address后面添加一个".toString()"。一般情况下我们是省略的。

而如果你不重写这个方法就会去父类找这个方法。(一定会有,顶级父类Object中有这个方法)

toString()是java中的一个内置方法,

其中"city"是Address类定义的一个属性,其对象为String,就会调用String类里面的toString()方法(String类中的toString()方法其实也是重写的Object中的方法,不详细将,会用就可以)

public class Address {
    String city;
}
class Test08{
    public static void main(String[] args) {
        Address address= new Address();
        System.out.println(address.toString());
        System.out.println(address);
        System.out.println(address.city);
    }
}
结果:task02.Address@1540e19d
    task02.Address@1540e19d
    null