类和对象
1.类和对象的初步认知 C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。 JAVA是基于面向对象的,关注的是对象,将一件事拆分成不同的对象,靠对象之间交互完成。 例如:洗衣服 面向过程:  面向对象: 面向过程注重的是过程,在整个过程中所涉及到的行为就是功能。 面向对象注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个一个功能实现连接起来的。
2.类和类的实例化 类就是一类对象的统称。对象就是这一类具体化的一个实例。 简单的例子:我们做月饼的模子就相当于一个类,而通过这个模子可以做出月饼。在这个例子当中,类就好比是这个模子,对象就好比是这个月饼。一个类可以实例化出无数个对象。 声明一个类就是创建一个新的数据类型,而类在Java中属于引用类型,Java使用关键字class来声明类。 基本语法
//创建类 class <class_name>{ field;//成员属性 method;//成员方法 } //实例化对象 <class_name> <对象名> = new <class_name>();
class 为定义类的关键字,<class_name>为类名,{}中为类的主体。 类中的元素称为:属性。类中函数称为:成员方法。 实例:
class Person{
public int age;
public String name;
public Sting sex;
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
注意事项 和之前写的方法不同,此处写的方法不带static关键字。后边我们会详细解释static是干啥的。 类的实例化
- 类只是一个模型一样的东西,限定了类有哪些成员。
- 一个类可以实例化出许多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量。
- 做个比方。实例化出对象就像现实中使用建筑设计图建造出房子,类就是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间。
class Person{
public int age;
public String name;
public String sex;
public void eat(){
System.out.println("吃法!");
}
public void sleep(){
System.out.println("睡觉!");
}
}
public class Main(){
public static void main(String[] args) {
Person person = new Person();
person.eat();
person.sleep();
Person person2 = new Person();
Person person3 = new Person();
}
}
输出结果:
吃饭! 睡觉!
注意事项:
- new关键字用于创建一个对象的实例化
- 使用符号(.)来访问对象中的属性和方法
- 同一个类可以创建多个实例
3.类的成员 类的成员可以包括以下:字段、方法、代码块、内部类和接口等。 此处我们重点介绍前三个 3.1字段/属性/成员变量 在类中,但是在方法外部定义的变量,这样的变量我们称为“字段”或“属性”或“成员变量”(这三种称呼都可以,一般不会严格区分) 用于描述一个类中包含哪些数据。
class Person {
public int age = 18;
public String name = "张三";
}
class Test{
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.age);
System.out.println(person.name);
}
}
3.2方法(method) 这就是我们曾经讲过的方法 用于描述一个对象的行为
class Person {
public int age = 18;
public String name = "张三";
public void show(){
System.out.println("我叫" + name + "," + "今年" + age + "岁");
}
}
class Test{
public static void main(String[] args) {
Person person = new Person();
person.show();
}
}
此处的show方法,表示Person这个对象具有一个"展示自我"的行为。 这样的show方法是和person实例相关的。如果创建了其他实例,那么show的行为就会发生变化。
Person person2 = new Person();
person2.name = "李四";
person2.age = 23;
person2.show();
3.3 static 关键字
- 修饰属性
- 修饰方法
- 代码块
- 修饰类
a)修饰属性,Java静态属性和类相关,和具体的实例无关,换句话说,同一个类的不同实例共用同一个静态属性。
class TestDemo{
public int a;
public static int count;
}
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所修饰 ,所有类共享。且不属于对象,访问方式为:类名.属性。
b)修饰方法 如果在任何方法是应用static关键字,此方法称为静态方法。
- 静态方法使用类,而不属于类的对象
- 可以直接调用静态方法,而无需创建类的实例
- 静态方法可以访问静态数据成员,并可以更改数据成员的值。
class TestDemo{
public int a;
public static int count;
public static void change(){
count = 100;
}
}
class Main{
public static void main(String[] args) {
TestDemo.change();
System.out.println(TestDemo.count);
}
}
注意事项1:静态方法和实力无关,而是和类相关,因此导致了这两个情况。
- 静态方法不能直接使用非静态数据成员或调用非静态方法(非静态数据成员和方法都是和实例相关的)。
- this和super两个关键字不能在静态上下文中使用(this是当前实例的引用,super是当前实例父类实例的引用,也是和当前实例相关的)。
注意事项2
- 我们曾经写的方法为了简单,都统一加上了static.但实际上一个方法具体要不要带static,都需要是情形而定的。
- main方法为static方法。
3.4 小结 观察以下代码,分析内存布局。
class Person {
public int age;
public String name;
public String sex;
public static int count;
public final int SIZE = 10;
public static final int COUNT = 99;
public void eat() {
int a = 10;
System.out.println("eat()!");
}
public void sleep() {
System.out.println("sleep()!");
}
public static void staticTest() {
System.out.println("staticTest()");
}
}
class Main{
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.age);
System.out.println(person.name);
System.out.println(Person.count);
Person.staticTest();
person.eat();
person.sleep();
}
}
运行结果 0 null 0 staticTest() eat()! sleep()!
4.封装 什么叫封装 封装就是最基本的方法,在我们写代码的时候经常会涉及两种角色: 类的实现者(1号程序员)和类的调用者(2号程序员). 封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就行了. 这样就降低了类使用者的学习和使用成本, 从而降低了复杂程度.
4.1 private实现封装 private/public 这两个关键字表示"访问权限控制".
- 被public修饰的成员变量或者成员方法,可以直接被调用者使用。
- 被private修饰的成员变量或者成员方法,不能被类的调用者使用。
换句话说,类的使用这根本不需要知道,也不需要关注一个类都有哪些private的成员。从而让类的调用者以更低的成本来使用类。 直接使用public
class Person{
public String name = "张三";
public int age = 18;
}
class Test{
public static void main(String[] args) {
Person person = new Person();
System.out.println("我叫" + person.name + ",今年" + person.age + "岁");
}
}
- 这样的代码导致类的使用者(mian方法的代码)必须要了解Person类内部的实现,才能够使用这个类,学习成本较高
- 一旦类的实现者修改了代码(例如把name改成myname),那么类的使用者就要大量的修改自己的代码,维护成本太高。
范例:使用private封装属性,并提供public方法供类的调用者使用。
class Person{
private String name = "张三";
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.show();
}
}
此时字段已经使用 private 来修饰. 类的调用者(main方法中)不能直接使用. 而需要借助 show 方法. 此时类的使用者就不必了解 Person 类的实现细节. 同时如果类的实现者修改了字段的名字, 类的调用者不需要做出任何修改(类的调用者根本访问不到 name, age 这样的字段,不用管).
当然了,类的实现者万一修改了pubilc方法show,调用者依然需要修改大量方法,这种情况有可能发生。但是,基于道德底线,一般没人这么干。
4.2 getter 和 setter方法 当我们使用private来修饰字段的时候,就无法直接使用这个字段了。 代码示例
class Person{
private String name = "张三";
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();
}
}
此时如果需要获取或者修该这个private属性,就需要使用getter/setter方法 代码示例
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void show(){
System.out.println("name:" + name + "age:" + age);
}
public static void main(String[] args) {
Person person = new Person();
person.setName("caocao");
String name = person.getName();
System.out.println(name);
person.show();
}
}
caocao
name:caocao age:0
(1)这里的getter和setter方法我们可以自己写,也可以按快捷键Alt+insert,快速生成或者右(2)键Generate——>Getter,Setter选中你要生成的属性,生成即可。 (3)当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值. this 表示当前对象的引用.,而不是当前的对象。 (4)getName 即为 getter 方法, 表示获取这个成员的值。 (5)setName 即为 setter 方法, 表示设置这个成员的值。 5.构造方法 5.1基本语法 构造方法是一种特殊的方法,使用关键字new实例化新对象是会被自动调用,用于完成初始化操作。 实例化一个对象(new执行过程)分两步 (1)为对象分配内存。 (2)使用合适的构造方法(构造方法不止一个)。 语法规则
-
1.方法名必须与类的名称相同。 -
2.构造方法没有返回值类型声明。 -3. 每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造) 注意事项 -
如果类中没有提供任何的构造函数,那么编译器就会默认生成一个不带有参数的构造函数。 -
若类中定义了构造函数,则默认的无参构造将不再生成。 -
构造方法支持重载,规则和普通方法的重载一致。
在这里插入代码片
5.2this关键字 this表示当前对象的应用(注意不是当前对象)可以借助this来访问对象的字段和方法。
class Person {
private String name;
private int age;
private String sex;
public Person() {
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();
}
我们会发现在构造函数的内部,我们可以使用this关键字,构造函数是用来构造对象的,对象还没有构造好,我们就使用了this,那this还代表当前对象吗?当然不是,this代表的是当前对象的引用。
6.认识代码块
字段的初始化方式有:
就地初始化
使用构造方法初始化
使用代码块初始化
前两种方式前面已经学习过了, 接下来我们介绍第三种方式, 使用代码块初始化
6.1 什么是代码块 使用 {} 定义的一段代码,根据代码块定义的位置以及关键字,又可分为以下四种:
普通代码块 : 普通代码块:定义在方法中的代码块.
构造块:定义在类中的代码块(不加修饰符)。也叫实例代码块。构造代码块一般用于初始化实例成员变量。
静态块 :使用static定义的代码块。一般用于初始化静态成员属性
同步代码块(后续讲解多线程部分再谈)
6.2 普通代码块 普通代码块:定义在方法中的代码块
class Main{
public static void main(String[] args) {
{
int x = 10;
System.out.println("x1 = " + x);
}
int x = 100;
System.out.println("x2 = " + x);
}
}
6.3 构造代码块 构造块:定义在类中的代码(不加修饰符)。也叫实例代码块。构造代码块一般用于初始化实例成员变量。
class Person{
private String name;
private int age;
private String sex;
public Person(){
System.out.println("I am Person init()!");
}
{
this.name = "bit";
this.age = 12;
this.sex = "man";
System.out.println("I am instance init()!");
}
public void show(){
System.out.println("name:" + name + " age:" + age + " sex:" + sex);
}
}
class Main{
public static void main(String[] args) {
Person p1 = new Person();
p1.show();
}
}
I am instance init()!
I am Person init()!
name:bit age:12 sex:man
注意事项:实例代码块优先于构造函数执行。 6.4 静态代码块 使用static定义的代码块。一般用于初始化静态成员属性
class Person{
private String name;
private int age;
private String sex;
private static int count = 0;
public Person(){
System.out.println("I am Person init()!");
}
{
this.name = "bit";
this.age = 12;
this.sex = "man";
System.out.println("I am instance init()!");
}
static {
count = 10;
System.out.println("I am static init()!");
}
public void show(){
System.out.println("name:" + name + " age:" + age + " sex:" + sex);
}
}
class Main{
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
}
}
执行结果 I am static init()! I am instance init()! I am Person init()! I am instance init()! I am Person init()!
注意事项:
- 静态代码块无论生成多少个对象,其只会执行一次,且是最先执行的。
- 静态代码块执行完毕后,实例代码块(构造块)执行,然后是构造函数执行。
7 匿名对象 匿名只是表示没有名字的对象
- 没有引用的对象称为匿名对象
- 匿名对象只能在创建对象时使用
- 如果一个对象只是使用一次,后边不需要了,可以考虑使用匿名对象
代码实例
class Person{
private String name;
private int age;
public Person(String name,int age){
this.age = age;
this.name = name;
}
public void show(){
System.out.println("name: " + name + " age:" + age);
}
}
public class TestDemo{
public static void main(String[] args) {
new Person("caocao",19).show();
}
}
|