对类和对象的认识
类(class)是构造对象的模板或者蓝图。类也是一类对象的统称,而对象即就是类具体化的一个实例,一个类可以产生无数的对象。而在Java中我们如何来声明一个类呢? 声明一个类就是创建一个新的数据类型,而类在 Java 中属于引用类型, Java 使用关键字 class 来声明类。以下就是简单的声明一个类: 基本语法:
// 创建类 class <class_name>{ field;//成员属性 method;//成员方法 } // 实例化对象 <class_name> <对象名> = new <class_name>();class为定义类的关键字,ClassName为类的名字,{}中为类的主体。类中的元素称为:成员属性。类中的函数称为:成员方法。 而我们用类的类型创建对象的过程,称为类的实例化。
类只是类似一个模型,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它。一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量。 我们需要注意的是:new 关键字用于创建一个对象的实例;使用 . 来访问对象中的属性和方法;同一个类可以创建对个实例。 而在类的内部成员有:字段、方法、代码块、内部类和接口等。 字段 (field) 在类中, 但是方法外部定义的变量.用于描述一个类中包含哪些数据. class Person { public String name; // 字段 public int age; } class Test { public static void main(String[] args) { Person person = new Person(); System.out.println(person.name); System.out.println(person.age); } } // 执行结果 null 0注意事项: 使用 . 访问对象的字段 “访问” 既包含读, 也包含写 对于一个对象的字段如果没有显式设置初始值, 那么会被设置一个默认的初值. 默认值规则: 对于各种数字类型, 默认值为 0. 对于 boolean 类型, 默认值为 false. 对于引用类型(String, Array, 以及自定制类), 默认值为 null 认识 null null 在 Java 中为 “空引用”, 表示一个无效的对象. 类似于 C 语言中的空指针. 如果对 null 进行 . 操作就会引发异常.
class Person { public String name; public int age; } class Test { public static void main(String[] args) { Person person = new Person(); System.out.println(person.name.length()); // 获取字符串长度 } } // 执行结果 Exception in thread "main" java.lang.NullPointerException//java.lang.NullPointerException为空指针异常 at Test.main(Test.java:9)字段就地初始化 很多时候我们不希望字段使用默认值, 而是需要我们显式设定初值. 可以这样写:
class Person { public String name = "Sunray"; public int age = 22; } class Test { public static void main(String[] args) { Person person = new Person(); System.out.println(person.name); System.out.println(person.age); } } // 执行结果 Sunray 22方法 (method) 用于描述一个对象的行为. 方法中还有一种特殊的方法称为 构造方法 (construction method)在实例化对象的时候会被自动调用到的方法,方法名字和类名相同, 用于对象的初始化(使用关键字new实例化新对象时会被自动调用, ).虽然我们前面已经能将属性就地初始化, 但是有些时候可能需要进行一些更复杂的初始化逻辑, 那么就可以使用构造方法.如果不提供构造方法,系统会给出默认构造方法.多个构造方法存在是以重载的形式存在的.如果定义了有参数的构造方法,这时系统不会再添加没有参数的构造方法. 构造方法格式: 1.方法名和类名相同. 2.不用定义返回值类型,void也不需要定义. 3.无具体返回值. this关键字 this表示当前对象引用(注意不是当前对象). 可以借助 this 来访问对象的字段和方法this表示当前对象引用(注意不是当前对象). 可以借助 this 来访问对象的字段和方法.
class Person { private String name;//实例成员变量 private int age; private String sex; //默认构造函数 构造对象 public Person() { //this调用构造函数 this("bit", 12, "man");//必须放在第一行进行显示 } //这两个构造函数之间的关系为重载。 public Person(String name,int age,String sex) { this.name = name; this.age = age; this.sex = sex; } public void show() { System.out.println("name: "+name+" age: "+age+" sex: "+sex); } } public class Main{ public static void main(String[] args) { Person person = new Person();//调用不带参数的构造函数 person.show(); } } // 执行结果 //name: bit age: 12 sex: man在构造函数的内部,我们可以使用this关键字,构造函数是用来构造对象的,对象还没有构造好, 我们就使用了this,那this还代表当前对象吗?,this代表的是当前对象的引用 static 关键字 1、修饰属性 Java静态属性和类相关, 和具体的实例无关. 换句话说, 同一个类的不同实例共用同一个静态属性
class TestDemo{ public int a; public static int count; } public class Main{ public static void main(String[] args) { TestDemo t1 = new TestDemo(); t1.a++; TestDemo.count++; System.out.println(t1.a); System.out.println(TestDemo.count); System.out.println("============"); TestDemo t2 = new TestDemo(); t2.a++; TestDemo.count++; System.out.println(t2.a); System.out.println(TestDemo.count); } } /*输出结果为: 1 1 ============ 1 2 */count被static所修饰,所有类共享。且不属于对象,访问方式为:类名 . 属性 2、修饰方法 如果在任何方法上应用 static 关键字,此方法称为静态方法。静态方法属于类,而不属于类的对象。可以直接调用静态方法,而无需创建类的实例。静态方法可以访问静态数据成员,并可以更改静态数据成员的值。
class TestDemo{ public int a; public static int count; public static void change() { count = 100; //a = 10; error 不可以访问非静态数据成员 } } public class Main{ public static void main(String[] args) { TestDemo.change();//无需创建实例对象 就可以调用 System.out.println(TestDemo.count); } } //输出结果为:100注意事项1: 静态方法和实例无关, 而是和类相关. 因此这导致了两个情况:
静态方法不能直接使用非静态数据成员或调用非静态方法(非静态数据成员和方法都是和实例相关的).this和super两个关键字不能在静态上下文中使用(this 是当前实例的引用, super是当前实例父类实例的引用, 也 是和当前实例相关). 注意事项2: 我们曾经写的方法为了简单, 都统一加上了 static. 但实际上一个方法具体要不要带 static, 都需要是情形而定. main 方法为 static 方法 3、代码块 4、修饰类 封装 封装(encapsulation)。 从形式上看, 封装是将数据和行为组合在一个包中, 并对对象的使用者隐藏了数据的实现方式。对象中的数据称为实例域(instancefield), 操纵数据的过程称为方法(method。) 对于每个特定的类实例(对象)都有一组特定的实例域值。这些值的集合就是这个对象的当前状态(state)。 无论何时, 只要向对象发送一个消息, 它的状态就有可能发生改变。实现封装的关键在于绝对不能让类中的方法直接地访问其他类的实例域。 程序仅通过对象的方法与对象数据进行交互。 封装给对象赋予了“ 黑盒” 特征,提高重用性和可靠性 。 这意味着一个类可以全面地改变存储数据的方式, 只要仍旧使用同样的方法操作数据,其他对象就不会知道所发生的变化。 private实现封装: private/ public 这两个关键字表示 “访问权限控制” . 被 public 修饰的成员变量或者成员方法, 可以直接被类的调用者使用;被 private 修饰的成员变量或者成员方法, 不能被类的调用者使用. getter和setter方法 当我们使用 private 来修饰字段的时候, 就无法直接使用这个字段: class Person { private String name = "xx"; private int age = 18; public void show() { System.out.println("我叫" + name + ", 今年" + age + "岁"); } } class Test { public static void main(String[] args) { Person person = new Person(); person.age = 20; person.show(); } }编译出错 Test.java:13: 错误: age可以在Person中访问private person.age = 20; ^ 1 个错误 此时如果需要获取或者修改这个 private 属性, 就需要使用 getter / setter 方法:
class Person { private String name;//实例成员变量 private int age; public void setName(String name){ this.name = name;//this引用,表示调用该方法的对象 } public String getName(){ return name; } public void show(){ System.out.println("name: "+name+" age: "+age); } } public static void main(String[] args) { Person person = new Person(); person.setName("xx"); String name = person.getName(); System.out.println(name); person.show(); }// 运行结果 xx name: xx age: 0 注意事项: 1.当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值. this 表示当前实例 的引用. 2.不是所有的字段都一定要提供 setter / getter 方法, 而是要根据实际情况决定提供哪种方法. 在 IDEA 中可以使用 alt + insert (或者 alt + F12) 快速生成 setter / getter 方法. 在 VSCode 中可以使用鼠标右键 菜单 -> 源代码操作 中自动生成 setter / getter 方法 代码块 代码块:使用 {} 定义的一段代码. 根据代码块定义的位置以及关键字,又可分为以下四种:
普通代码块:定义在方法中的代码块.构造块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量。静态块:使用static定义的代码块。一般用于初始化静态成员属性。注意事项: 1.静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。 2.静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行。同步代码块我们都知道C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。 而Java是面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。 面向过程注重的是过程,在整个过程中所涉及的行为,就是功能。 面向对象注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来。 简而言之面向对象就是用代码(类)来描述客观世界的事物的一种方式. 一个类主要包含一个事物的属性和行为。 开发时:找(构造)对象,建对象,用对象,并维护对象之间的关系。 区分对象和对象变量 在对象与对象变量之间存在着一个重要的区别。例如, 语句 Date deadline; 定义了一个对象变量 deadline, 它 可 以 引 用 Date 类型的对象。 但是,一定要认识到: 变量 deadline 不是一个对象, 实际上也没有引用对象。 此时, 不能将任何 Date 方法应用于这个变量上。 语句 s = deadline.toStringO; 将产生编译错误。 必须首先初始化变量deadline, 这里有两个选择。当然,可以用新构造的对象初始化这 个变量: deadline = new Date() ; 也让这个变量引用一个已存在的对象: deadline = birthday; 现在, 这两个变量引用同一个对象 一个对象变量并没有实际包含一个对象,而仅仅引用一个对象。 在Java中,任何对象变量的值都是对存储在另外一个地方的一个对象的引用。new操作符的返回值也是一个引用。我们可以将Java的对象变量看作C++的指针。