-
面向对象基本概念
- 面向过程:以步骤为单位,一步一步完成某一个具体的事情
- 面向对象:以对象为单位,通过调度组合不同的对象来完成某一个事情
-
类与对象
-
类:是一组具有相同特性(属性)与行为(方法)的事物集合
-
类与对象的关系:
- 类表示一个共性的产物,是一个综合的特征;对象是一个个性的产物,是一个个体的特征
- 类由属性和方法组成
- 属性:就相当于一个个的特征
- 方法:就相当于人的一个个的行为
-
类与对象的定义格式
-
类的格式:
// 类的格式 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
-
-
封装性
// 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关键字:访问权限修饰符,公有的属性或方法,可以被类外部的其他类访问
- 通常在一类中,属性都私有化,并对外提供setter和getter方法
- 成员变量和局部变量:
- 在类中的位置不同:
- 成员变量:在类中定义
- 局部变量:在方法中定义或者方法的参数
- 在内存中的位置不同:
- 成员变量:在堆内存(成员变量属于对象,对象进堆内存)
- 局部变量:在栈内存(局部变量属于方法,方法进栈内存)
- 生命周期不同:
- 成员变量:随着对象的创建而存在,随着对象的销毁而消失
- 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
- 初始化值不同:
- 成员变量:有默认初始化值,引用类型默认为null
- 局部变量:没有默认初始化值,必须定义,赋值,然后才能使用
- 注:局部变量名称和成员变量名称一样,在方法中使用的时候,采用的是就近原则
- 在类中的位置不同:
-
构造方法
// 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(){},构造方法私有化,当我们的需求是为了保证该类只有一个对象时
- 注:工具类(没有属性的类,只有行为)并且该工具对象被频繁使用。权衡只用一个对象与产生多个对象的内存使用,来确定该类是否要定义为只需要一个对象
-
-
this关键字
- this关键字可以完成以下的操作:
- 调用类中的属性
- 调用类中的方法或构造方法
- 表示当前对象
- 表示当前对象:在方法被调用的过程中,那个对象调用了方法,在方法内的this就表示谁
- 在方法中使用this调用类中的其他方法或属性,this可以省略,this前面可以使用当前的类名.this
- this关键字可以完成以下的操作:
-
值传递与引用传递
-
值传递
// 值传递 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 = 贝贝
-
-
对象的一对一关系
// 英雄类 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);
-
-
static关键字
- static关键字的作用:
- 使用static关键字修饰一个属性:声明为static的变量实质上就是全局变量
- 使用static关键字修饰一个方法:通常,在一个类中定义一个方法为static,那就是说,无需本类的对象即可调用此方法
- 使用static关键字修饰一个类(内部类)
- static关键字:
- 静态变量或方法不属于对象,依赖类
- 静态变量是全局变量生命周期从类被加载后一直到程序结束
- 静态变量只会存一份,在静态方法区中存储
- 静态变量是本来所有对象共享一份
- 建议不要使用对象名去调用静态数据,直接使用类名调用
- static修饰一个方法,那么该方法属于类,不属于对象,建议直接用类名调用
- 静态方法不能访问非静态属性和方法,只能访问静态
- 不能以任何方式引用this或super
- 所有对象共有的属性或方法时,我们可以定义为静态的
- static关键字的作用:
-
main方法分析
// 主方法 public static void main(String[] args) { // 代码块 } public:公有的,最大的访问权限 static:静态的,无需创建对象 void:表示没有返回值,无需向JVM返回结果 main:方法名,固定的方法名 String[] args:表示参数为字符串数组,可以在调用方法时传入参数
-
代码块
-
普通代码块:在方法中写的代码块
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("构造方法"); } }
- 在第一次使用的时候被调用(创建对象),只会执行一次,静态代码块优于构造代码块执行。我们在项目开发中,通常会使用静态代码块来初始化只调用一次的数据
-
同步代码块:(多线程中讲解)
-
-
单例设计模式
-
单例设计模式:保证一个类只有一个实例,并提供一个访问它的全局访问点
-
单例实现步骤:
- 构造方法私有化
- 声明一个本类对象
- 给外部提供一个静态方法获取对象实例
-
两种实现方式:
-
饿汉式(也叫主动实例化):在类被加载后,对象被创建,到程序结束后释放(占用内存的时间长,提高效率)
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() { } }
-
-
对象数组与管理
-
对象数组:数组里的每个元素都是类的对象,赋值时先定义对象,然后将对象直接赋给数组
// 使用对象数组实现多个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); } }
-