java基础(三)

day_01

值传递和引用传递的理解:

1、值传递

    在方法的调用过程中,实参把它的实际值传递给形参,此传递过程就是将实参的值复制一份传递到函数中,这样如果在函数中对该值(形参的值)进行了操作将不会影响实参的值。因为是直接复制,所以这种方式在传递大量数据时,运行效率会特别低下。

2、引用传递

    引用传递弥补了值传递的不足,如果传递的数据量很大,直接复过去的话,会占用大量的内存空间,而引用传递就是将对象的地址值传递过去,函数接收的是原始值的首地址值。在方法的执行过程中,形参和实参的内容相同,指向同一块内存地址,也就是说操作的其实都是源数据,所以方法的执行将会影响到实际对象。

面试的时候简单描述:

  1. 基本数据类型传值,对形参的修改不会影响实参;
  2. 引用类型传引用,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象。
  3. String, Integer, Double等immutable的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象。

 

 

 

 

1.静态修饰符
注意:可以去修饰 成员变量(属性或者字段),不可以修饰 类(外部类),构造方法,局部变量


有static修饰的字段和方法,我们可以用字段所在的类的 类名.字段  类名.方法去访问
没有用static修饰的字段和方法,只能用实例去访问它,即创建对象去调用。
注意:
1.静态的属性放在 类的数据区 内, 所以 每个对象访问静态属性的时候 都是去 类的数据区中访问的静态属性的值
2.对象的数据区 中不包含静态属性。
3.一般情况下,类中的全局常量 用static修饰的较多,而类中的 字段 很少使用static修饰

 

static修饰的属性和方法在什么时候加载到类数据区里?
当程序编译时,该类中用到的所有类,这些类都会编译,然后这些的静态属性和静态方法都会被加载到类的数据区里去,看下图:

 2. 封装 思想:对内部细节进行封装(隐藏),对外只提供能使用的方式,封装的目的是安全。

访问权限修饰符
  作用:主要用来修饰类中的成员(属性,普通方法,构造方法),也可以去修饰类

  private :该修饰符只能在本类中访问
  default(缺省不写):在不同包下面不可以访问
  protected:在不同包下面不可以访问
  public:在任何地方都可以访问
注意:
  1.public 、默认的(缺省不写) 这两种可以去修饰类(外部类,内部类)
  2.private 和protected 不能去修饰外部类
  3.所有的访问权限修饰符都不可以去修饰 局部变量
总结:
4. 公共的修饰(public):成员方法  字段(可以去修饰但是一般情况下用private修饰),构造方法, 内部类 ,类
私有的修饰(private): 字段,,成员方法(一帮情况成员方法用public修饰),构造方法 ,内部类

  

javabean:是一个标准的java类
  要求:
    1.类必须要是public修饰的
    2.类中的属性必须是private修饰的
    3.类中必须提供一个无参数构造器
    4.每个私有化的属性必须提供一组getter/setter方法

  注意: 1.Boolean类型(布尔的包装类),生成的get方法是get开头的(建议使用这个). 
      2.boolean类型,生成的get方法是is开头的   (用这个最好重写 getXxx() 格式的方法,

      因为涉及到反射,反射一般会默认调取对象的get方法) 

 

3. this关键字

  用法:
  1.在方法中出现的this代指调用该方法的对象
  2.this可以解决属性与局部变量同名时的冲突

Public Class Student { 
   String name; //定义一个成员变量name
   private void SetName(String name) { //定义一个参数(局部变量)name
      this.name=name; //将局部变量的值传递给成员变量
   }
}

  

 


  3.this可以调用构造方法(注意:this必须是构造器中的第一条语句)

public class Student { //定义一个类,类的名字为student。 
     public Student() { //定义一个方法,名字与类相同故为构造方法
        this(“Hello!”);
     }
     public Student(String name) { //定义一个带形式参数的构造方法
     }
}

  


  4.this可以作为方法的返回值返回的是调用this所处方法的那个对象的引用,更简单点说,就是谁调用返回的就是谁。

  由于返回的是对象引用,所以this不能用在静态成员方法中,只能在非静态成员方法中出现。

  详细参考:https://www.cnblogs.com/chanchan/p/7812166.html


  5.this可以作为方法的调用时的实参
  6.this在自定义类型中的使用(同桌问题,一定要理解)

   

 1 class People {
 2     private String name;
 3     private People friend;
 4     public void setName(String name){
 5          this.name = name;
 6     }
 7     public String getName(){
 8         return this.name;
 9     }
10     public void setFriend(People friend){
11          if(this.getFriend() == friend){
12             return;
13          }
14          this.friend = friend;
15          friend.setFriend(this);//此种方式注意死循环
16     }
17     public People getFriend(){
18         return this.friend;
19     }
20 }
21 
22 public class TestPeople {
23     public static void main(String[] args) {
24         People p1 = new People();
25         p1.setName("小王");
26         
27         People p2 = new People();
28         p2.setName("小张");
29 
30         //设置朋友关系
31         p1.setFriend(p2);
32         System.out.println(p1.getName()+"的朋友是:"+p1.getFriend().getName());
33         //p2.setFriend(p1);
34         System.out.println(p2.getName()+"的朋友是:"+p2.getFriend().getName());
35     }
36 }

 day02

1.继承

子类继承父类中某些成员  ,  父类(超类,基类,根类),子类(派生类,拓展类)

  泛化:在多个子类的基础上面抽取共有的属性和行为到一个父类中去。

  特化:在一个父类 的基础上拓展子类的特有属性和行为,生成一个新的子类。

  原则:父类中存在共性,子类中存在特性。  

  优势:  提高代码的复用性。  

  子类可以去继承哪些成员?1.非私有化的成员(字段,方法) 2.private修饰的成员以及构造方法不能被继承

继承的特点
  1.在java程序中继承只允许单继承(一个子类只允许有一个直接父类)
  2.在java程序中允许每个类之间多重继承 eg: A extends B, B extends C C extends D
  3.如果类都没有去直接继承另外一个类,那么该类会默认继承 超级基类(Object类)

 

 

 

2.方法的重写

概念:将父类的方法复制到子类重新定义方法体内的代码的过程

子类中拥有一个和父类完全一样(有几点可以不一样)的方法,将这两个方法称为重写

方法重写的要求:

    1.保证子类方法和父类方法的方法签名(方法名+参数列表)一致,其中形参的名称是否一样无所谓

    2.(访问权限等级高低   public >  默认的  > private)

      子类的方法的    访问修饰符的等级  等于或者大于   父类的方法的访问修饰符

    3.private修饰的方法不能被重写(private修饰的成员方法不能被继承到子类)

    4.static修饰的方法不能被重写(static修饰的方法存在类的数据区,不在对象数据区)

    5.子类中重写的方法的返回值类型 与 父类方法返回值类型 相同或者是父类的返回值类型的子类(不是java中的等级高低)

注意:

1.在编译阶段验证是否覆写: 在子类方法上面加 @Override ,用来检测子类中的方法是否重写父类的方法,让编译器来检查,如果是正确的覆写,编译通过,否则编译报错

2.子类方法和父类方法完全一样,也是方法的重写。

 

 

 3.Object类

注意:★(所有的引用数据类型的对象都属于Object类型)

  1.Object类位于java.lang包下面,使用时不需要导包

  2.所有的引用数据类型的对象都可以使用Object类里的方法

  3.基本数据类型变量 不可以使用Object类里的方法

toString()

哪个对象调用toString()方法,该方法就返回该对象的字符串表示形式

如果对象所属的类中没有重写toString,那么对象访问的是Objet类中toString方法

    如果对象所属的类中重写了toString ,那么对象访问的是他自己本身类中重写的toString方法

  注意:在自定义类中重写toString()的方法是因为打印对象名时,不想看到l类似这样"Student@56dd8cc"的值,而是想清楚的知道对象的属性值是什么。

 

equals方法

1.Object中的equals怎么定义的?

1 //lang包--   Object.java  中的equals();
2     public boolean equals(Object obj) {
3         return (this == obj);
4     }

 

  2.  String 中的equals怎么定义的?

 1 //lang包--  String.java 中的equals();
 2     public boolean equals(Object anObject) {
 3         if (this == anObject) {
 4             return true;
 5         }
 6         if (anObject instanceof String) {
 7             //强制转换,装箱。
 8             String anotherString = (String)anObject;
 9 //            value指前面的需要比较的字符串
10             int n = value.length;
11             if (n == anotherString.value.length) {
12                 char v1[] = value;
13                 char v2[] = anotherString.value;
14                 int i = 0;
15                 while (n-- != 0) {
16                     if (v1[i] != v2[i])
17                         return false;
18                     i++;
19                 }
20                 return true;
21             }
22         }
23         return false;
24     }

  3.Object 和String 中的toString();

1 //   Object 中的toString();
2     public String toString() {
3         return getClass().getName() + "@" + Integer.toHexString(hashCode());
4     }
5 //   String 中的toString();
6     public String toString() {
7         return this;
8     }

 

  4.自定义类中的equals方法怎么定义?

 1 //自定义类中的equals方法
 2     public boolean equals(Student stu) {
 3         if(((this.getName()).equals(stu.getName())) && ((this.getStuId())==(stu.getStuId()))){
 4             return true;
 5         }
 6         return false;
 7     }
 8 /*    1.编译器看到的obj的类型是  Object ,Object中是没有name和age的,编译报错
 9     但是,我们知道实际调用的时候obj变量中装的是一个学生对象,
10     应该明确的告诉编译器这个obj是学生对象---》 obj强制转换成 Student*/
11 /*    2.this.name  其实类型是String 是引用类型(非常特殊的引用类型) ; 
12     使用== 比较有风险(可能比较的是地址),应该比较字符串的字面值
13     String类在设计的时候就于已经覆写了Object中的equals方法,比较规则就是使用的字面值进行比较
14     所以 上面this.name == s.getName()    应该调用String类中的equals方法*/
15     public boolean equals(Object obj) {
16         Student s = (Student)obj;
17         if(this.name.equals(s.getName())&&this.age == s.getAge()){
18             return true;
19         }
20         return false;
21     }
22 /*    3.上面的代码 if中的条件 本身就是一个逻辑运算,逻辑运算表达式的结果值就是一个boolean
23     所以没有必要写if   else*/
24     public boolean equals(Object obj) {
25         Student s = (Student)obj;
26         return this.name.equals(s.getName())&&this.age == s.getAge();
27     }

 

  ★★:5.为什么调用println方法会  自动调用toString方法?

 1 //io包--PrintStream.java 里面的println();
 2       public void println(Object x) {
 3         String s = String.valueOf(x);
 4         synchronized (this) {
 5             print(s);
 6             newLine();
 7         }
 8     }
 9     
10 //lang包--String.java 里面的valueOf();
11     public static String valueOf(Object obj) {
12         return (obj == null) ? "null" : obj.toString();
13     }

 

4.== equals 都是比较是否相等,请问它们到底有什么区别呢?

    相等 :  a 传统的理解一般都是数字值是否相等;

           b 在程序中任何东西都是数据,都会比较是否相等

1  ==

  基本数据类型:    比较的就是值是否相等;

      引用数据类型:    比较的是对象的地址是否一样;(排除特殊 String

2 equals  (最初定义在根类Object中的)

基本数据类型 :  不能够使用!   基本数据类型不是对象,不能够调用Object中的方法

引用数据类型 :  Object的源码中定义的就是==进行比较比较,比较的是对象的地址是否一样

         而在String类型和包装类型(Integer)都重写了equals方法,比较是对应的值。

在实际开发中,我们一般比较对象都是通过对象的属性值进行比较(一般比较对象的地址没有多大用处),所以我们会经常覆写Object中的此方法,把自己的规则写在方法里面;

 

 

hashcode()

哈希码:该对象的内存地址通过JVM换算的一个10进制数字

 

day03 

1.反编译  将字节码文件编译成java文件。

      首先bin目录下要有jad.exe  .

      

 

2. super关键字
  作用:调用父类中的成员(属性,成员方法,构造方法)

  1.在子类的方法中使用,代指父类对象,可以去调用父类属性和方法

  2.在子类的构造方法 里访问父类的构造方法  用super() 调用无参父类构造方法。用super( 参数列表) 调用有参父类构造方法。

  3.子类的构造器中的第一行代码会默认隐藏一个 super() ,当子类构造器中书写了super()或者this()的 (有参无参 )时,构造器中的隐藏的super()会被覆盖。

       4.super() 和 this() 表达式 必须是构造器中的第一条语句,导致了super(),this()不能在构造器中同时使用,
    
使用场景:
  1.super可以去访问父类中的非私有化的成员
  2.调用父类构造方法(在子类构造器中 对父类私有化的属性进行初始化值)
  3.子类构造器中第一条语句默认存在super();

 

3.多态

  1.概念:一种事物(对象)有多种形态(类型)可以屏蔽不同的子类之间的实现差异,多态是指通过指向父类的指针,来调用在不同子类中实现的方法。

    多态形式创建对象:
      定义类型  对象名  = new 实际类型( );
      定义类型:父类, 实际类型是:子类  ,也就是定义了一个 指向子类 的 父类引用类型 的 对象

 

  2.多态方法调用编译和运行时的过程。

  上面两句代码的编译,运行过程:

  编译 :  第三行, 如果AnimalPerson的父类,那么编译通过,否则编译报错;

           第四行, (编译器把p1看成是Animal) 编译的时候会到p1的编译类型中找是否有eat方法,如果没有,会继续向p1的编译类型的父类中一直向上找,如果都没有找到,编译报错, 如果找到了编译通过

        (不会向下到子类中去找找的时候就是编译的时候是不会执行代码的)

  运行 : 第四行 , 先到运行时类型(Person)eat方法,如果找到就执行,否则就向上到父类中找并执行

 

  1.多态形式创建的对象可以调用哪些属性和方法,取决于定义类型

  2.多态形式创建的对象的实际类型(子类)中,方法发生了重写,那么该对象调用的是子类中的方法
  3.字段没有覆写一说

  实际开发中一般不会在子类中定义一个和父类同名的字段,如果是有这样的情况存在,如果是使用的父类的对象,取值是父类里面的值; 如果子类对象,取值是子类里面的值;

  也就是父类类型的引用可以调用父类中定义的所有属性和方法

 

参考:http://www.cnblogs.com/chenssy/p/3372798.html

   http://www.cnblogs.com/hai-ping/articles/2807750.html

 

 

3.引用类型转换
  小转大(向上转型):将子类对象 赋值给 父类对象的变量保存的过程,此时自动转换

  大转小(向下转型):将父类对象 赋值给 子类对象的变量的过程,但此时需要强转

  注意一般在开发中遇到向下转型时,都会对该对象的实际类型进行判断

  boolean is = obj(目标对象) instanceof Type(目标对象类型)

 

4.final 关键字

  final 修饰的类不能有子类,即不能被继承。

  final 不能修饰构造方法,final修饰的方法不能被重写。

  final 修饰的常量要初始化,且不能更改。(final修饰的常量要么直接赋值,要么使用有参或者无参的构造方法进行初始化,使用setter方法赋值会报错)

  final 修饰的对象的引用不能改变。列如数组和对象的变量引用。

 

day04

1.单例模式 (介绍五种)  1. 饿汉模式   2. 懒汉模式   3.  双重检测锁模式  4.  枚举   5. 静态内部类模式:


  单例类必须自己创建自己唯一的实例(对象)

 1 //饿汉模式
 2 public class Student {
 3 //私有化无参的构造方法,其他类就不可以随便创建对象了。
 4     private Student(){};
 5 //私有的,静态的对象,创建一次地址就不会改变,必须通过方法来访问
 6     private static Student s = new Student();
 7 //静态的方法,外部直接使用  类名.方法 调用
 8     public static Student getInstance(){
 9         return s;
10     }
11 }
 1 //懒汉模式
 2 public class Teacher {
 3     
 4     private Teacher(){};
 5     
 6     private static Teacher t = null;
 7     public static Teacher getInstance(){
 8 //if语句为了 防止在堆内存空间创建不同的对象 而 违反了单例原则
 9         if(t == null){
10             t = new Teacher();
11         }
12         return t;
13     }
14 }

 

  1 单例模式的类也是一个普通的类,其中也可以有其他的字段  方法等。。。

  2 上面代码中,s对象是Student类被加载(把类放到JVM的过程中)的时候创建的

  3 如果Student类中其他的字段和方法很多。。。,创建对象的过程比较长,类加载会比较慢

   有可能加载之后很长时间其实都没有人来获得对象,浪费堆内存空间,这就是饿汉模式

  4 在类加载的时候先不创建对象,而是在有人第一次来调用方法获得对象的时候才创建一个对象

   之后需要保存起来,以后再有人调用就不用创建对象。这就是懒汉模式

总结:
  饿汉模式,类加载的时候效率低,获取单例对象时效率高,线程安全
  懒汉模式,类加载的时候效率高,获取单例对象时效率低,线程不安全

 

懒汉模式的非线程安全问题的解决方法:双重检测锁模式

首先使用同步代码块,同步方法,效率低下;使用DCL(Double-Check Locking)双检查锁机制-

 

双重判空的的意义:

 

对于person1存在的情况,就直接返回。当person1为null并且同时存在两个线程调用getPerson1()方法时,它们都将通过第一重的person1==null的判断。

 

然后由于类锁机制,这两个线程只有一个可以获得锁并进入,另一个在外排队等候,必须要其中一个进入并出来后,另一个才能进入。

 

而此时如果没有了第二重的person1==null是否为null的判断,则第一个线程创建了实例,而第二个线程获得锁后还是可以继续再创建新的实例,这就没有达到单例的目的。

 

public class Person1 {  
    private static volatile Person1 person1 =null;  
    private Person1(){  
        }  
    public static Person1 getPerson1() {  
        if(person1==null){  
            synchronized(Person1.class){  
                if(person1==null)  
                person1=new Person1();  
            }  
        }  
        return person1;  
    }  
}  

 

静态内部类模式:

public class SingleTon{
  private SingleTon(){}
 
  private static class SingleTonHoler{
     private static SingleTon INSTANCE = new SingleTon();
 }
 
  public static SingleTon getInstance(){
    return SingleTonHoler.INSTANCE;
  }
}

 

  

 

2.代码块
  构造代码块(初始化代码块,非静态代码块)

    直接定义在类中,当调用了构造方法时,会先执行构造代码块(没有构造代码块就只执行自己)


  普通代码块
  (局部代码块):通常定义在方法内结合if switch 循环去使用


  静态代码块   简述类加载的初始化顺序?
  1静态初始化块只在类加载时执行,且优先于主方法执行,且只会执行一次,同时静态初始化块只能给静态变量赋值,不能初始化普通的成员变量。
  2.可以在类加载的时候对静态的属性进行初始化
总结:
  1.所有的静态代码块先执行,从顶级父类开始依次往后加载
  2.在同一个构造器中,super() 优先于 构造代码块 优先于 构造器中的语句
  3.当构造器中的第一条语句是this()时,构造器中构造代码块不存在了

 

day05

1.抽象类   理解:   我们都知道在面向对象的领域一切都是对象,同时所有的对象都是通过类来描述的,但是并不是所有的类都是来描述对象的。如果一个类没有足够的信息来描述一个具体的对象,而需要其他具体的类来支撑它,那么这样的类我们称它为抽象类。

  1.使用abstract修饰的类是抽象类,抽象类本质也是一个类

  2.类中有的成员  抽象类都可以有(字段 方法  构造方法),此外抽象类还比普通类多一个抽象方法, 故抽象类不允许创建对象。当然,抽象类中可以没有抽象方法。

  3.抽象方法:用abstract修饰的方法 ,它没有方法体,并且定义时最后结束加;而且抽象方法 必须存于抽象类中(接口也可以),不能够放在普通类中。

  4.一般将抽象的类作为父类, (普通)子类继承抽象父类,必须重写所有父类中的抽象方法。当然,如果子类也是抽象类,可以不用去重写父类中的抽象方法。

注意:abstarct 不能修饰属性,因为属性没有必要实现。

   接口引用指向实现类的对象  比如:List list = new ArrayList();

 

2.接口  理解:接口本身就不是类, 接口是抽象类的延伸,接口是用来建立类与类之间的协议,它只提供一种形式,而没有具体的实现。

       同时实现该接口的实现类  必须  要 实现该接口的所有方法,通过使用implements关键字,他表示该类在遵循 某个或 某组 特定的接口。

       java为了保证数据安全是不能多重继承的,也就是说继承只能存在一个父类,但是接口不同,一个类可以同时实现多个接口,

      不管这些接口之间有没有关系,所以接口弥补了抽象类不能多重继承的缺陷,但是推荐继承和接口共同使用,因为这样既可以保证数据安全性又可以实现多重继承。

 

   接口定义: interface 接口名{}

 

    接口内部可以有哪些成员--参考类

      字段   全部都是全局常量(public static final修饰), 故可以直接调用

      方法   全部都是抽象方法(缺省修饰 public abstract)(接口中可以没有抽象方法,但是没意义)

         抽象方法需要子类类覆写才有意义,而static final修饰的方法都不能够被覆写,接口中的方法不可以用 static ,final修饰

       接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;  

      构造方法  没有!

    注意

      1.接口主要强调的是功能,必须要有实现类去实现(实现的时候注意public修饰符)

      2.接口相当于实现类的父类(多态时体现),类可以去实现多个接口,类与类单继承,一个接口可以去继承多个接口,但接口不可以去实现接口 。

  接口和抽象的区别:
    1.接口概念
    2.抽象概念

    3. 相同点:  1. 抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。

              2. 抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类还只能是抽象类。

            同样,一个类实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。


    4. 不同点  

       1. 抽象层次不同。抽象类是对类抽象,而接口是对行为的抽象。即  抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。

       2. 跨域不同。抽象类所跨域的是具有相似特点的类,而接口却可以跨域不同的类。

             例如猫、狗可以抽象成一个动物类抽象类,具备叫的方法。鸟、飞机可以实现飞Fly接口,具备飞的行为,这里我们总不能将鸟、飞机共用一个父类吧!

             所以说抽象类所体现的是一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在"is-a" 关系,即父类和派生类在概念本质上应该是相同的。对于接口则不然,

             并不要求接口的实现者和接口定义在概念本质上是一致的, 仅仅是实现了接口定义的契约而已。

       3.设计层次不同。对于抽象类而言,它是自下而上来设计的,我们要先知道子类才能抽象出父类,而接口则不同,它根本就不需要知道子类的存在,只需要定义一个规则即可,

               至于什么子类、什么时候怎么实现它一概不知。

               比如我们只有一个猫类在这里,如果你这是就抽象成一个动物类,是不是设计有点儿过度?我们起码要有两个动物类,猫、狗在这里,我们在抽象他们的共同点

               形成动物抽象类吧!所以说抽象类往往都是通过重构而来的!但是接口就不同,比如说飞,我们根本就不知道会有什么东西来实现这个飞接口,怎么实现也不得而知,

               我们要做的就是事前定义好飞的行为接口。所以说抽象类是自底向上抽象而来的,接口是自顶向下设计出来的。 

 

3.谈谈你对面向对象的理解

         面向对象是向现实世界模型的自然延伸,这是一种“万物皆对象”的编程思想。在现实生活中的任何物体都可以归为一类事物,而每一个个体都是一类事物的实例。

  面向对象的编程是以对象为中心,以 消息为驱动,所以程序=对象+消息。

    面向对象有三大特性,封装、继承和多态。

    封装就是将一类事物的属性和行为抽象成一个类,使其属性私有化,行为公开化,提高了数据的隐秘性的同时,使代码模块化。这样做使得代码的复用性更高。

      继承则是进一步将一类事物共有的属性和行为抽象成一个父类,而每一个子类是一个特殊的父类--有父类的行为和属性,也有自己特有的行为和属性。这样做扩展了已存在的代码块,进一步提高了代码的复用性。

    如果说封装和继承是为了使代码重用,那么多态则是为了实现接口重用。多态的一大作用就是为了解耦--为了解除父子类继承的耦合度。如果说继承中父子类的关系式IS-A的关系,那么接口和实现类之之间的关系式HAS-A。简单来说,多态就是允许父类引用(或接口)指向子类(或实现类)对象。很多的设计模式都是基于面向对象的多态性设计的。

总结一下,如果说封装和继承是面向对象的基础,那么多态则是面向对象最精髓的理论。掌握多态必先了解接口,只有充分理解接口才能更好的应用多态。

4.面向对象和面向过程的区别?

做菜为例,其实面向过程就好像你是个厨师,要自己炒菜,所以要讲究步骤,

而面向对象就好像你是个食客,你只要通知厨师作菜,即发一个消息就可以了,至于厨师怎样作菜,是不用知道的。
---------------------------------------------------

两句话:

面向过程是一种以事件为中心的编程思想。就是分析出解决问题所需的步骤,然后用函数把这些步骤实现,并按顺序调用。(一种自顶向下的编程。

面向对象是以“对象”为中心的编程思想。(自下向上先建立抽象模型然后再使用模型)。

 

5.面向对象开发的六个基本原则,迪米特法则

单一职责:一个类只做它该做的事情(高内聚)。在面向对象中,如果只让一个类完成它该做的事,而不设计与它无关的领域就是践行了高内聚的原则,这个类就只有单一职责。

开放封闭:软件实体应当对扩展开放,对修改关闭。要做到开闭有两个要点。第一、抽象是关键,一个系统中如果没有抽象类或接口系统就没有扩展点;第二、封装可变性,将系统中的各种可变因素封装到一个继承结构中,如果多个可变因素混杂在一起,系统将变得复杂而混乱。

里式替换:任何时候都可以用子类型替换掉父类型。子类一定是增加父类的能力而不是减少父类的能力,因为子类比父类的能力更多,把能力多的对象当成能力少的对象来用当然没有任何问题。

依赖倒置:面向接口编程(该原则说得直白和具体一些就是声明方法的参数类型、方法的返回类型、变量的引用类型时,尽可能使用抽象类型而不用具体的类型,因为抽象类型可以被它的任何一个子类型所替代)。

合成聚合复用:优先使用聚合或合成关系复用的代码。

接口隔离:接口要小而专,绝不能大而全。臃肿的接口是对接口的污染。既然接口表示能力,那么一个接口只应该描述一种能力,接口也应该是高内聚的。

迪米特法则
  迪米特法则又叫最少知识原则,一个对象应当对其他对象有尽可能少的了解。

项目中用到的原则
  单一职责、开放封闭、合成聚合复用(最简单的例子就是String类)、接口隔离。

 

6.枚举

 当我们遇到  属性值是固定值个数(属性值有确定范围)正常来可以使用单例模式,我们在类中使用单例模式需要创建本类的对象,当我们声明多个对象时,public static final及构造器就是重复性的代码,而枚举简化了创建本类对象时的格式,从而简化了单例模式的声明的方式。即枚举能够解决属性值是固定个数的问题

看下面代码使用单利模式解决属性值确定范围的问题。显然重复性代码居多。

 

package cm.单例模式解决属性范围问题;
// 以知人的性别只有男女之分,固属性值固定。
public class Gender {
    private Gender(){}
    
    private static Gender man = new Gender();
    private static Gender woman = new Gender();
    
//外部通过方法获取私有的对象    
    public static Gender getMan() {
        return man;
    }
    public static Gender getWoman() {
        return woman;
    }

//重写toString方法
     public String toString(){
         if(this == man){
             return "男";
         }else if(this == woman){
            return  "女";
         }
        return null;
     }
}

 

package cm.单例模式解决属性范围问题;

public class Student {
    private Gender gender;

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }
    

}
package cm.单例模式解决属性范围问题;

public class Test {

    public static void main(String[] args) {
        Student s = new Student();
        
        s.setGender(Gender.getMan());
        //打印对象
        System.out.println(s.getGender());  //
    }

}

看下面代码使用 枚举 解决 季节这个属性值固定问题

 1 package cm.枚举;
 2 
 3 public enum Season {
 4     spring("春",1),summer("夏",2),autumn(),winter("冬",4);
 5     
 6     private String name = "哈哈"; //初始值
 7     private int index;
 8     
 9     public String getName() {
10         return name;
11     }
12     public void setName(String name) {
13         this.name = name;
14     }
15     public int getIndex() {
16         return index;
17     }
18     public void setIndex(int index) {
19         this.index = index;
20     }
21 // 私有的有参的构造方法
22     private Season(String name,int index){
23         this.name = name;
24         this.index = index;
25     }
26 //私有的无参构造方法  ,这样枚举对象里面可以不用传值。
27     private Season(){}
28 //重写toString();
29     public String toString(){
30          return this.name+""+this.index;
31      }
32     
33     
34 }
 1 package cm.枚举;
 2 
 3 import cm.枚举星期.Week;
 4 
 5 public class Test {
 6 
 7     public static void main(String[] args) {
 8         Season s =  Season.spring;   //通过枚举类名.对象名访问 固定不变的属性(对象)
 9         System.out.println(s);
10         
11         Season[] ss = Season.values();//获取枚举类中定义的所有的对象,返回一个枚举类型的对象数组
12         for (Season i : ss) {
13             System.out.println(i.getName()+","+i.getIndex());
14         }
15     }
16 
17 }
结果为:

  春1
  春,1
  夏,2
  哈哈,0
  冬,4

 

 

7.组合关系

 

  ①组合是(has-a)关系,而继承则是(is-a)关系;

  ② 组合关系在运行期决定,而继承关系在编译期就已经决定了。

  ③ 组合是在组合类和被包含类之间的一种松耦合关系,而继承则是父类和子类之间的一种紧耦合关系。

  ④ 当选择使用组合关系时,在组合类中包含了外部类的对象,组合类可以调用外部类必须的方法,而使用继承关系时,父类的所有方法和变量都被子类无条件继承,子类不能选择。

 

转载于:https://www.cnblogs.com/gshao/p/10023035.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值