1. 面向对象基本概念
    • 面向过程:以步骤为单位,一步一步完成某一个具体的事情
    • 面向对象:以对象为单位,通过调度组合不同的对象来完成某一个事情
  2. 类与对象
    • 类:是一组具有相同特性(属性)与行为(方法)的事物集合

    • 类与对象的关系:

      • 类表示一个共性的产物,是一个综合的特征;对象是一个个性的产物,是一个个体的特征
      • 类由属性和方法组成
        • 属性:就相当于一个个的特征
        • 方法:就相当于人的一个个的行为
    • 类与对象的定义格式

      • 类的格式:

        // 类的格式
        class 类名称 {
            属性名称;
            返回值类型 方法名称() {
                // 方法内容
            }
        }
        
      • 对象的定义:一个类要想真正的进行操作,则必须依靠对象,对象的定义格式如下:

        // 对象的定义
        类名称 对象名称 = new 类名称();
        
      • 注:如果要想访问类中的属性或方法:

        // 访问类中的属性
        对象.属性;
        // 访问类中的方法
        对象.方法();
        
      • 对象声明有两种含义:

        // 表示声明了一个对象,但是此对象无法使用,horse没有具体的内存指向
        声明对象:Horse horse = null;
        
        // 表示实例化了对象,可以使用
        实例化对象:horse = new Horse();
        
        // 通过对象调用方法
        horse.eat();
        
        // 匿名对象调用方法
        new Horse().ear();
        
    • 对象与内存分析

      • new关键字的作用:

        • 创建一个对象
        • 实例化对象
        • 申请内存空间
      • 对象内存分析:

        // 对象在内存中的结构
        // horse存储在栈内存中,horse = null表示还没有申请空间
        Horse horse = null;
        // horse存储的是堆内存的地址,此时horse在堆内存中申请了空间,存储horse的属性
        horse = new Horse();
        
        // 给对象的属性赋值
        // horse存储在栈内存中,horse存储堆内存的地址,给堆内存中的name,age属性赋值
        horse.name = "小白";
        horse.age = 4;
        
        // 在内存中创建的多个对象
        // horse1和horse2都存储在栈内存区域中
        Horse horse1 = null;
        Horse horse2 = null;
        // 对象horse1和horse2实例化并申请堆内存空间,其中String类型初始化为null,int类型初始化为age
        horse1 = new Horse();
        horse2 = new Horse();
        // 分别给两个对象的属性赋值
        // 给堆内存中的对象属性赋值
        horse1.name = "小白";
        horse1.age = 4;
        horse2.name = "小黑";
        horse2.age = 5;
        
        // 声明两个对象,一个实例化,一个没实例化
        // 声明两个对象horse1和horse2
        Horse horse1 = null;
        Horse horse2 = null;
        // 将对象horse1实例化,给分配堆内存空间
        horse1 = new Horse();
        // 对象之间的赋值
        // 给对象horse1中的属性赋予初始值
        horse1.name = "小白";
        horse1.age = 4;
        // 将对象horse1所存储的地址赋值给对象horse2,即现在对象horse1和horse2指向同一片堆内存区域
        // 相同类型的对象才可以赋值
        horse2 = horse1;
        // 修改相同的堆内存区域中的name属性
        horse2.name = "小黑";
        
        // 对象之间的赋值
        Horse horse1 = new Horse();
        Horse horse2 = new Horse();
        // 分别给horse1和horse2的属性赋值
        horse1.name = "小黑";
        horse1.age = 4;
        horse2.name = "小白";
        horse2.age = 5;
        // 将horse1中存储的地址赋值给horse2,此时horse2所对应的堆内存区域成为垃圾
        // 此时horse2所对应的堆内存区域被JVM的GC程序认为是垃圾
        horse2 = horse1;
        // 此时horse1和horse2指向同一片堆内存区域,修改的是horse1对象的name属性
        horse2.name = "嘿嘿";
        
    • 注:一个对象在内存中的大小,由该对象的所有属性所占的内存大小的总和。引用类型变量在32位系统上占4个字节,在64位系统上占8个字节。还要算上其隐性数据所占的大小

    • 注:编程时,在确定不使用对象时,要尽早的释放对象,对象=null

  3. 封装性
    // Person类
    class Person {
        private String name;
        private int age;
        
        public void setName(String name) {
            this.name = name;
        }
        
        public String getName() {
            return name;
        }
        
        public void setAge(int age) {
            this.age = age;
        }
        
        public int getAge() {
            return age;
        }
    }
    
    • 封装性是面向对象思想的三大特征之一
    • 封装就是隐藏实现细节,仅对外提供访问接口
    • 封装有:属性的封装、方法的封装、类的封装、组件的封装、模块化封装、系统级封装…
    • 封装的好处:
      • 模块化
      • 信息隐藏
      • 代码重用
      • 插件化易于调试
      • 具有安全性
    • 封装的缺点:
      • 影响执行效率
    • 封装性:
      • 如果属性没有封装,那么在本类之外创建对象后,可以直接访问属性
      • private关键字:访问权限修饰符,表示私有的属性或方法,只能在本类中访问。要想在外部访问私有属性,我们需要提供公有的方法来间接访问
      • public关键字:访问权限修饰符,公有的属性或方法,可以被类外部的其他类访问
      • 通常在一类中,属性都私有化,并对外提供settergetter方法
    • 成员变量和局部变量:
      • 在类中的位置不同:
        • 成员变量:在类中定义
        • 局部变量:在方法中定义或者方法的参数
      • 在内存中的位置不同:
        • 成员变量:在堆内存(成员变量属于对象,对象进堆内存)
        • 局部变量:在栈内存(局部变量属于方法,方法进栈内存)
      • 生命周期不同:
        • 成员变量:随着对象的创建而存在,随着对象的销毁而消失
        • 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
      • 初始化值不同:
        • 成员变量:有默认初始化值,引用类型默认为null
        • 局部变量:没有默认初始化值,必须定义,赋值,然后才能使用
      • 注:局部变量名称和成员变量名称一样,在方法中使用的时候,采用的是就近原则
  4. 构造方法
    // Dog类
    class Dog {
        private String String;
        private int age;
    }
    
    • 构造方法的概念:

      • 构造方法就是类构造对象时调用的方法,用于对象的初始化工作
      • 构造方法就是实例化一个类非对象时,也就是new的时候,最先调用的方法
    • 构造方法的定义:

      // 构造方法定义的格式
      类名() {
      }
      
      // 对象的实例化语法
      // new Dog后面有一个括号,带括号表示调用了方法,此时调用的方法就是构造方法
      Dog dog = new Dog();
      
      • 构造方法定义的格式:方法名称与类名称相同,无返回值类型的声明
    • 无参数的构造方法:

      // 无参数的构造方法
      // 默认的构造方法,通常保留默认的构造方法
      public Dog() {
          System.out.println("无参数的构造方法!");
      }
      
    • 带一个参数的构造方法:

      // 带一个参数的构造方法
      public Dog(String name) {
          this.name = name;
          System.out.println("带一个参数的构造方法!");
      }
      
    • 带两个参数的构造方法:

      // 带两个参数的构造方法
      public Dog(String name, int age) {
          this.name = name;
          this.age = age;
      }
      
    • 构造方法之间的调用:

      // 构造方法之间的调用
      // 构造方法调用时要有出口
      public Dog(String name, int age) {
          // 在调用其他的构造方法时此语句必须在第一句
          this(name);// 调用带一个参数的构造方法
          this.age = age;
      }
      
    • 小结:

      • 构造方法名称与类名相同,没有返回值声明(包括void
      • 构造方法用于初始化数据(属性)
      • 每一个类中都会有一个默认的无参的构造方法
      • 如果类中有显示的构造方法,还想保留默认的构造方法,需要显示的写出来
      • 构造方法可以有多个,但参数不一样,称为构造方法的重载
      • 在构造方法中调用另一个构造方法,使用this(…),该句代码必须在第一句
      • 构造方法之间的调用,必须要有出口
      • 给对象初始化数据可以使用构造方法或setter()方法,通常情况下,两者都会保留
      • 一个好的编程习惯是要保留默认的构造方法(为了方便一些框架代码使用反射来创建对象)
      • private Dog(){},构造方法私有化,当我们的需求是为了保证该类只有一个对象时
        • 注:工具类(没有属性的类,只有行为)并且该工具对象被频繁使用。权衡只用一个对象与产生多个对象的内存使用,来确定该类是否要定义为只需要一个对象
  5. this关键字
    • this关键字可以完成以下的操作:
      • 调用类中的属性
      • 调用类中的方法或构造方法
      • 表示当前对象
    • 表示当前对象:在方法被调用的过程中,那个对象调用了方法,在方法内的this就表示谁
    • 在方法中使用this调用类中的其他方法或属性,this可以省略,this前面可以使用当前的类名.this
  6. 值传递与引用传递
    • 值传递

      // 值传递
      public class ValuePassing {
      	public static void main(String[] args) {
      		int x = 10;
      		method(x);
      		System.out.println("x = " + x);
      	}
      
      	public static void method(int m) {
      		m = 20;
      	}
      }
      
      // 输出
      x = 10
      
    • 引用传递

      // 引用传递
      public class ReferencePassing {
      	public static void main(String[] args) {
      		Duck d = new Duck();
      		method(d);
      		System.out.println("Dock age = " + d.age);
      	}
      	
      	public static void method(Duck duck) {
      		duck.age = 5;
      	}
      }
      
      class Duck {
      	int age = 2;// 省略封装
      }
      
      // 输出
      Dock age = 5
      
    • String传递

      // String传递
      // 字符串本身就是一个对象
      public class ReferencePassing {
      	public static void main(String[] args) {
      		String name = "小飞";
      		method(name);
      		System.out.println("name = " + name);
      	}
      	
      	public static void method(String sname) {
      		sname = "小贝";
      	}
      }
      
      // 输出
      name = 小飞
      
    • String传递

      // String传递
      public class ReferencePassing {
      	public static void main(String[] args) {
      		Person p = new Person();
      		method(p);
      		System.out.println("Person person = " + p.name);
      	}
      	
      	public static void method(Person person) {
      		person.name = "贝贝";
      	}
      }
      
      class Person {
      	String name = "飞飞";// 省略封装
      }
      
      // 输出
      Perso perso = 贝贝
      
  7. 对象的一对一关系
    // 英雄类
    class Hero {
    	private String name;
    	private int age;
    	// 一对一的关系
    	private Weapon weapon;
    
    	public Hero() {
    	}
    
    	public Hero(String name, int age) {
    		this.name = name;
    		this.age = age;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public int getAge() {
    		return age;
    	}
    
    	public void setAge(int age) {
    		this.age = age;
    	}
    
    	public Weapon getWeapon() {
    		return weapon;
    	}
    
    	public void setWeapon(Weapon weapon) {
    		this.weapon = weapon;
    	}
    
    }
    
    // 兵器类
    class Weapon {
    	private String name;
    	private int grade;
    	private Hero hero;
    
    	public Weapon() {
    	}
    
    	public Weapon(String name, int grade) {
    		this.name = name;
    		this.grade = grade;
    	}
    
    	public String getName() {
    		return name;
    	}
    
    	public void setName(String name) {
    		this.name = name;
    	}
    
    	public int getGrade() {
    		return grade;
    	}
    
    	public void setGrade(int grade) {
    		this.grade = grade;
    	}
    
    	public Hero getHero() {
    		return hero;
    	}
    
    	public void setHero(Hero hero) {
    		this.hero = hero;
    	}
    }
    
    • 在主函数中进行对象关系的关联:

      // 把两个对象关联
      hero.setWeapon(weapon);
      weapon.setHero(hero);
      
  8. static关键字
    • static关键字的作用:
      • 使用static关键字修饰一个属性:声明为static的变量实质上就是全局变量
      • 使用static关键字修饰一个方法:通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法
      • 使用static关键字修饰一个类(内部类)
    • static关键字:
      • 静态变量或方法不属于对象,依赖类
      • 静态变量是全局变量生命周期从类被加载后一直到程序结束
      • 静态变量只会存一份,在静态方法区中存储
      • 静态变量是本来所有对象共享一份
      • 建议不要使用对象名去调用静态数据,直接使用类名调用
      • static修饰一个方法,那么该方法属于类,不属于对象,建议直接用类名调用
      • 静态方法不能访问非静态属性和方法,只能访问静态
      • 不能以任何方式引用thissuper
    • 所有对象共有的属性或方法时,我们可以定义为静态的
  9. main方法分析
    // 主方法
    public static void main(String[] args) {
        // 代码块
    }
    
    public:公有的,最大的访问权限
    static:静态的,无需创建对象
    void:表示没有返回值,无需向JVM返回结果
    main:方法名,固定的方法名
    String[] args:表示参数为字符串数组,可以在调用方法时传入参数
    
  10. 代码块
    • 普通代码块:在方法中写的代码块

      public class OrdinaryCodeBlock {
      	public static void main(String[] args) {
      		{
      			// 普通代码块
      			String infoString = "局部变量1";
      			System.out.println(infoString);
      		}
      		String infoString = "局部变量2";
      		System.out.println(infoString);
      	}
      }
      
    • 构造代码块:在类中定义的代码块

      class Demo {
          {
              // 构造块
              System.out.println("构造块");
          }
         
          public Demo() {
              System.out.println("构造方法.");
          }
      }
      
      • 在创建对象时被调用,优于构造方法执行
    • 静态代码块:在类中使用static声明的代码块称为静态代码块

      class Demo {
          {
              System.out.println("构造代码块");
          }
          static {
              System.out.println("静态代码块");
          }
          
          public Demo() {
              System.out.println("构造方法");
          }
      }
      
      • 在第一次使用的时候被调用(创建对象),只会执行一次,静态代码块优于构造代码块执行。我们在项目开发中,通常会使用静态代码块来初始化只调用一次的数据
    • 同步代码块:(多线程中讲解)

  11. 单例设计模式
    • 单例设计模式:保证一个类只有一个实例,并提供一个访问它的全局访问点

    • 单例实现步骤:

      • 构造方法私有化
      • 声明一个本类对象
      • 给外部提供一个静态方法获取对象实例
    • 两种实现方式:

      • 饿汉式(也叫主动实例化):在类被加载后,对象被创建,到程序结束后释放(占用内存的时间长,提高效率)

        public class SingleCaseDesignPattern {
            public static void main(String[] args) {
                SingleCase singleCase = SingleCase.getInstance();
                singleCase.print();
            }
        }
        
        // 饿汉式
        class SingleCase {
            private SingleCase() {}
            
            private static SingleCase singleCase = new SingleCase();
            
            public static SingleCase getInstance() {
                return singleCase;
            }
            
            public void print() {
                System.out.println("饿汉式单例设计模式");
            }
        }
        
      • 懒汉式(也叫被动实例化):在第一次调用getInstance方法时,对象被创建,到程序结束后释放(占用内存的时间短,效率稍低),也叫作懒加载或延迟加载

        public class SingleCaseDesignPattern {
            public static void main(String[] args) {
                SingleCase singleCase = SingleCase.getInstance();
                singleCase.print();
            }
        }
        
        // 懒汉式
        class SingleCase {
            private SingleCase() {}
            
            private static SingleCase singleCase;
            
            public static SingleCase getInstance() {
                if (singleCase == null) {
                    singleCase = new SingleCase();
                }
                return singleCase;
            }
            
            public void print() {
                System.out.println("懒汉式单例设计模式");
            }
        }
        
    • 使用单例设计模式:

      • 在设计一些工具类的时候(通常工具类,只有功能方法没有属性)
      • 工具类可能会被频繁调用
    • 单例设计模式的目的:为了节省重复创建对象所带来的内存消耗,从而带来效率

    • 使用构造方法私有化+静态方法:

      class Tools {
          private Tools() {}
          
          public static void print1() {
          }
          
          public static void print2() {
          }
      }
      
  12. 对象数组与管理
    • 对象数组:数组里的每个元素都是类的对象,赋值时先定义对象,然后将对象直接赋给数组

      // 使用对象数组实现多个Chicken的管理
      Chicken[] chicken = new Chicken[10];
      
    • 举例:

      import java.util.Arrays;
      
      /** * * @author xiao儿 * * 动态数组: * 1.数组是一种线性数组结构 * 2.数组不适合进行删除插入等操作,适合添加、查找、遍历操作 */
      public class ArraysOfObjects {
      	public static void main(String[] args) {
      		ChickenManager chickenManager = new ChickenManager(5);
      		// 添加
      		chickenManager.add(new Chicken(1, "小小", 10));
      		chickenManager.add(new Chicken(2, "小二", 8));
      		chickenManager.add(new Chicken(3, "小三", 6));
      		chickenManager.add(new Chicken(4, "小四", 4));
      		chickenManager.add(new Chicken(5, "小五", 2));
      
      		chickenManager.add(new Chicken(6, "小豆", 1));
      		System.out.println("数组的长度是:" + chickenManager.length());
      
      		System.out.println("--------findAll---------");
      		chickenManager.printAll();
      
      		System.out.println("--------find-----------");
      		Chicken chicken = chickenManager.find(5);
      		chicken.print();
      		
      		System.out.println("--------update----------");
      		chickenManager.update(new Chicken(1, "下蛋公鸡", 20));
      		chickenManager.printAll();
      		
      		System.out.println("--------delete-----------");
      		chickenManager.delete(6);
      		chickenManager.printAll();
      	}
      }
      
      // 小鸡管理类
      class ChickenManager {
      	private Chicken[] chickens = null;
      	private int count = 0;// 当前数组的元素个数(下标)
      
      	public ChickenManager(int size) {
      		if (size > 0) {
      			chickens = new Chicken[size];
      		} else {
      			chickens = new Chicken[5];
      		}
      	}
      
      	public int length() {
      		return chickens.length;
      	}
      
      	// 添加:实现动态数组
      	public void add(Chicken chicken) {
      		if (count >= chickens.length) {// 数组已满,需要扩充
      			// 算法1:扩充原来数组大小的一半 chickens.length * 3 / 2 + 1
      			// 算法2:扩充原来数组的一倍 chickens.length * 2
      			int newLength = chickens.length * 2;
      			chickens = Arrays.copyOf(chickens, newLength);
      		}
      		chickens[count] = chicken;
      		count++;
      	}
      
      	// 删除
      	public void delete(int id) {
      		for (int i = 0; i < count; i++) {
      			if (chickens[i].getId() == id) {
      				// 找到了要删除的对象,把该对象之后的对象向前移动一起
      				for (int j = i; j < count - 1; j++) {
      					chickens[j] = chickens[j + 1];
      				}
      				// 把最后一个对象赋值为空(删除)
      				chickens[count - 1] = null;
      				count--;// 下标减一
      				break;
      			}
      		}
      	}
      
      	// 更新
      	public void update(Chicken chicken) {
      		Chicken tempChicken = find(chicken.getId());
      		if (tempChicken != null) {
      			tempChicken.setNameString(chicken.getNameString());
      			tempChicken.setAge(chicken.getAge());
      		}
      	}
      
      	// 查找
      	public Chicken find(int id) {
      		for (int i = 0; i < count; i++) {
      			if (chickens[i].getId() == id) {
      				return chickens[i];
      			}
      		}
      		return null;
      	}
      
      	// 输出所有
      	public void printAll() {
      		for (int i = 0; i < count; i++) {
      			chickens[i].print();
      		}
      	}
      }
      
      // 小鸡类(数据对象)value object (VO)
      class Chicken {
      	private int id;
      	private String nameString;
      	private int age;
      
      	public Chicken() {
      	}// 一般情况下最好保留默认的构造方法
      
      	public Chicken(int id, String nameString, int age) {
      		this.id = id;
      		this.nameString = nameString;
      		this.age = age;
      	}
      
      	public int getId() {
      		return id;
      	}
      
      	public void setId(int id) {
      		this.id = id;
      	}
      
      	public String getNameString() {
      		return nameString;
      	}
      
      	public void setNameString(String nameString) {
      		this.nameString = nameString;
      	}
      
      	public int getAge() {
      		return age;
      	}
      
      	public void setAge(int age) {
      		this.age = age;
      	}
      
      	public void print() {
      		System.out.println("id = " + id + ",name = " + nameString + ",age = " + age);
      	}
      }