- 1.引入类和对象
- 1.引出对象
- 2.类
- 静态成员变量 ( static )
- 小结
- 2补充toString方法
- 3.封装
- 1.枯燥的概念
- 2.private 实现封装
- 4.¥构造方法
- 5. this关键字
- 6.代码块
我们学习类和对象,先抛出两个问题
1.什么是类?
2.什么是对象?
我们大家都洗过衣服,有两种,要不自己手洗
要不抛到洗衣机里让洗衣机帮我们洗。
那么手洗 就相当于 面向过程, 我们要独自完成一堆操作如放水放衣服等过程
而 用洗衣机 就是 面向对象,我们只需要 将衣服 抛进洗衣机 就行此时洗衣机 就相当于对象,由他完成一系列过程,我们只要结果就行。
在举一个例子,买手机,我们买手机是不是要考虑他的参数性价比等,需要上网自行了解,最后通过购物平台付款最后拿快递。
如果 我们有钱 雇佣了一个秘书,我们是不是可以直接叫秘书来完成以上这个操作,等待秘书将手机给我们。
所以 秘书是不是就相当于对象,我们通过对象来获取结果。
我们知道了对象,那么对象从何而来,答案是 类
2.类 简单的例子:我们做月饼的模子就是一个类,而通过这个模子可以做出月饼,那么在这个例子当中,类就是那个模 子,而月饼就是那个对象,所以月饼就是一个实体。一个模子可以实例化无数个对象。 总的来说:类相当于一个模板,对象是由模板产生的样本。一个类,可以产生无数的对象。 声明一个类就是创建一个新的数据类型,而类在 Java 中属于引用类型, Java 使用关键字 class 来声明类。我们来 看以下简单的声明一个类。public class Main {
static class Person {
字段 -> 属性 -> 成员变量->类的内部方法的外部
1.普通成员变量 2.静态成员变量
public String name;
public int age;
局部变量 方法的内部
成员变量 方法的外部
方法 -> 行为
1.普通成员变量 2.静态成员变量
public void eat() {
System.out.println(name+" 正在吃饭吃饭");
}
public void sleep() {
System.out.println(name+" 正在睡觉");
}
}
public static void main(String[] args) {
类的实例化
Person person = null;
类也相当于一个类型
比如 int a = 10; a 是一个变量 int 是一个类型
person 就是一个变量,Person 就为一个类型
由类定义的变量是引用变量所以可以赋值null
Person person = new Person();
此时就实例化了一个对象
Person person1 = new Person();
Person person2 = new Person();
Person person3 = new Person();
Person person4 = new Person();
Person person5 = new Person();
这就是通过 类 (模板)创建 了 多个对象
Person person = new Person();
// 为成员变量赋值
person.name = "laoba";
person.age = 18;
成员变量的访问需要对象的引用来访问
此时的成员变量为普通成员变量
System.out.println(person.name);
System.out.println(person.age);
此时打印 为 laoba 和 18
如过没有赋值 那么会打印 什么呢
Person person = new Person();
System.out.println(person.name);
System.out.println(person.age);
其实 在 成员变量没有赋初始值是 会 打印 默认值, 整形 为 0 浮点型 为 0.0 布尔类型为 false
引用数据类型 数组 , 类 , 接口 默认值 为 null
接下来 我们来 了解 创建 多个对象 是 如何创建
Person person1 = new Person();
person.name = "laoba";
person.age = 18;
System.out.println(person.name);
System.out.println(person.age);
System.out.println("==============");
Person person2 = new Person();
person1.name = "cxk";
person1.age = 99;
System.out.println(person1.name);
System.out.println(person1.age);
}
}
方法的使用 同 变量的使用 一样
public class Main {
static class Person {
//字段 -> 属性 -> 成员变量 1.普通成员变量
// 2.静态成员变量
public String name;
public int age;
//方法 -> 行为
// 1.普通成员变量 2.静态成员变量
public void eat() {
System.out.println(name+" 正在吃饭");
}
public void sleep() {
System.out.println(name+" 正在睡觉");
}
}
public static void main(String[] args) {
Person person = new Person();
此时为赋值,使用方法 name 是 String (引用)
name 默认值为null 随意是 null 正在吃饭,
null 正在睡觉
person.eat();
person.sleep();
System.out.println("================");
Person person2 = new Person();
person2.name = "laoba";
person2.eat();
person2.sleep();
}
}
静态成员变量 ( static )
class TestDemo{
a 为普通成员变量
public int a;
count 为静态成员变量
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);
}
}
解释 为啥 count 为 2
因为 count 是静态变量 存放在 方法区 ,只有一个count ,此时count加加了2次 所以为 2
}
}
这里我们继续
class Person {
// 普通的成员变量 都是属于对象的
public String name;
public int age;
//静态成员变量
public static int count;
public void eat() {
System.out.println(name + " 正在吃饭");
}
}
public class Main {
public static void main(String[] args) {
Person person1 = new Person();
person1.age++;
//person1.count++;
//这里编译器报警告,是因为
//静态成员变脸是不需要对象,意味着它属于类
Person.count++;
System.out.println(person1.age);
System.out.println(Person.count);
System.out.println("====================");
Person person2 = new Person();
person2.age++;
//person2.count++;
Person.count++
System.out.println(person2.age);
System.out.println(person2.count);
}
}
class Person {
// 普通的成员变量 都是属于对象的
public String name;
public int age;
//静态成员变量
public static int count;
public void eat() {
注意事项
static int size = 0;
在普通方法类不能定义静态成员变量
1.被static 修饰的是属于类的,这样定义就不是属于类属于方法了
假设能定义
2.eat 方法的调用需要 对象的引用来调用 如果可以定义static 的变量, 这个变量不需要对象
通过类名 Person 就可以调用
System.out.println(name + " 正在吃饭");
}
public void print() {
注意
staticFunc()--- 在普通方法里调用静态方法
这里不会报错 ,可以想 普通方法需要对象,静态方法不需要方法两部分不干扰,所以可以调用
如果在静态方法中调用普通呢?
System.out.println("姓名:"+name+" 年龄:"+age);
}
// 类方法
public static void staticFunc() {
注意
static int size = 10;
static 定义的属于类,此时定义的size 属于方法,所以做不到
注意2
println();
此时是在静态方法中调用普通方法,会发生错误
想一想 其实非常简单, 我们知道静态方法是不需要对象的,而普通方法是需要对象
将一个需要对象的 放进一个没有对象的那肯定会发生错误的。
如果你想在 静态方法中调用普通方法,可以创建一个对象让后调用,但一般不这么用。
Person person = new Person();
person.print();
System.out.println("static::func()");
}
}
public class Main {
public static void main(String[] args) {
//访问静态方法,直接通过类名来访问
Person.staticFunc();
Person p = new Person();
// p.eat();
//普通 需要 创建一个对象,通过对象来访问
p.print();
}
}
总结 静态的成员变量是不可以在方法中定义的
注意事项
static int size = 0;
在普通方法类不能定义静态成员变量
.被static 修饰的是属于类的,这样定义就不是属于类属于方法了
假设能定义
.eat 方法的调用需要 对象的引用来调用 如果可以定义static 的变量, 这个变量不需要对象
通过类名 Person 就可以调用
在 静态方法中
static int size = 10;
static 定义的属于类,此时定义的size 属于方法,所以做不到
总结 静态的成员变量是不可以在方法中定义的
. 普通方法 调用 静态方法
普通方法需要对象,静态方法不需要方法两部分不干扰,所以可以调用
如果在静态方法中调用普通呢?
静态方法中调用普通方法,会发生错误
想一想 其实非常简单, 我们知道静态方法是不需要对象的,而普通方法是需要对象
class Person {
public int age;//实例变量 存放在对象内
public String name;//实例变量
public String sex;//实例变量
public static int count;//类变量也叫静态变量,编译时已经产生,属于类本身,且只有一份。存放在方法区
public final int SIZE = 10;//被final修饰的叫常量,也属于对象。 被final修饰,后续不可更改
public static final int COUNT = 99;//静态的常量,属于类本身,只有一份 被final修饰,后续不可更
改
//实例成员函数
public void eat() {
int a = 10;//局部变量
System.out.println("eat()!");
}
//实例成员函数
public void sleep() {
System.out.println("sleep()!");
}
//静态成员函数
public static void staticTest(){
//不能访问非静态成员
//sex = "man"; error
System.out.println("StaticTest()");
}
}
public class Main{
public static void main(String[] args) {
//产生对象 实例化对象
Person person = new Person();//person为对象的引用
System.out.println(person.age);//默认值为0
System.out.println(person.name);//默认值为null
//System.out.println(person.count);//会有警告!
//正确访问方式:
System.out.println(Person.count);
System.out.println(Person.COUNT);
Person.staticTest();
//总结:所有被static所修饰的方法或者属性,全部不依赖于对象。
person.eat();
person.sleep();
}
}
fine 被final修饰的叫常量,也属于对象。 被final修饰,后续不可更改
fine修饰静态变量为静态的常量,属于类本身,只有一份 被final修饰,后续不可更该
另外一个变量存放在哪里和你是否被fine修改无关
这里我们继续来看代码
class Person {
// 普通的成员变量 都是属于对象的
public String name;
public int age;
//静态成员变量
public static int count;
public void eat() {
System.out.println(name + " 正在吃饭");
}
public void print() {
staticFunc();
System.out.println("姓名:"+name+" 年龄:"+age);
}
public static void staticFunc() {
Person person = new Person();
person.print();
System.out.println("static::func()");
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person();
person 是引用类型 存放的 是对象的地址
System.out.println(person);
我们将结果打印出来
}
@前面是类型, 后面是哈希值相当于地址,因为java 比较安全不能拿到真正的地址,拿到的是处理过的地址
我们自己实现一个toString
class Person {
public String name;
public int age;
public String toString() {
return "laoba";
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
//这里我们没有自己实现toString
//下面 我们自己实现一个toString
}
}
此时 调用了 我们自己的toString
继续上面这段代码
class Person {
public String name;
public int age;
public String toString() {
return "姓名:"+name+"年龄:"+age;
}
上面是我们自己写的,也可以通过编译器 快捷写出
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
}
3.封装 1.枯燥的概念toString 方法会在 println 的时候被自动调用.
将对象转成字符串这样的操作我们称为 序列化.
toString 是 Object 类提供的方法, 我们自己创建的 Person 类默认继承自 Object 类, 可以重写 toString 方法实
现我们自己版本的转换字符串方法. (关于继承和重写这样的概念, 我们后面会重点介绍).
@Override 在 Java 中称为 “注解”, 此处的 @Override 表示下面实现的 toString 方法是重写了父类的方法. 关于
注解后面的课程会详细介绍.
IDEA快速生成Object的toString方法快捷键:alt+f12(insert)
什么叫封装?
<<代码大全>> 开篇就在讨论一个问题: 软件开发的本质就是对程序复杂程度的管理. 如果一个软件代码复杂程
度太高, 那么就无法继续维护. 如何管理复杂程度? 封装就是最基本的方法.
我们写代码 涉及到 两种角色:类的实现者和类的调用者.
封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就行了.
这样就降低了类使用者的学习和使用成本, 从而降低了复杂程度
换句话说, 类的使用者根本不需要知道, 也不需要关注一个类都有哪些 private 的成员. 从而让类调用者以更低的 成本来使用类.
class Person {
//public String name;
//public int age;
private String name;
private int age;
public int age2;
//被private 修饰 说明被封装起来了
//只能在当前 类当中来使用(类外不能使用)
// 只是我们需要提供 get set 方法
public String getName() {
return name;
}
public void setName(String myName) {
name = myName;
}
public void setAge(int age) {
age = age; 这样赋值 会使age 为 0
因为 age 为局部变量会先使用相当于自己给自己使用,
类的age 根本没有赋值
改为
this age = age;
this 代表当前对象的引用 ,这里要加一个this 才能赋值
}
public void setAge2(int age ) {
age2 = age;
这里的age2 不会受 影响 age2 与 age 的变量名都不一样怎么会出现自使用呢
}
public int getAge2() {
return age2;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person();
person.setName("blaoba");
person.setAge2(10);
System.out.println(person.getName());
System.out.println(person.getAge2());
}
}
是不是有疑问 如果每个属性都要 手写一个get 和 set 方法 那是不是太麻烦了
其实 ,我们可以直接通过编译器来完成 get 和 set 方法的编写
class Person {
private String name;
private int 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;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
此时字段已经使用 private 来修饰. 类的调用者(main方法中)不能直接使用. 而需要借助 show 方法. 此时类的使
用者就不必了解 Person 类的实现细节.
同时如果类的实现者修改了字段的名字, 类的调用者不需要做出任何修改(类的调用者根本访问不到 name, age
这样的字段).
概念
构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用, 用于完成初始化操作.
new 执行过程
为对象分配内存空间
调用对象的构造方法
语法规则
1.方法名称必须与类名称相同
2.构造方法没有返回值类型声明
3.每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造)
注意事项
如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数
若类中定义了构造方法,则默认的无参构造将不再生成.
构造方法支持重载.规则和普通方法的重载一致。
class Person {
private String name;
private int age;
public Person() {
System.out.println("Person():: 不带参数的构造方法 ");
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person(); 括号里无参数 调用无参数的构造方法
这里实例化对象,为对象分配内存
调用合适的构造方法
}
}
class Person {
private String name;
private int 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 Person() {
System.out.println("Person():: 不带参数的构造方法 ");
}
public Person(String name) {
this.name = name; // this 当前对象的引用
System.out.println("带一个参数的构造方法");
}
public Person(String name,int age) {
this.name = name;
this.age = age;
System.out.println("带两个参数的构造方法");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
public class Main {
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("==============");
Person person2 = new Person("laoba");
System.out.println("==============");
Person person3 = new Person("laoba",15);
//这里实例化对象,为对象分配内存
//调用合适的构造方法
}
}
5. this关键字
this.data 调用当前对象的属性
this.func 调用当前对象的方法
this() 调用当前对象的其他构造方法 (存放在构造函数当中 ! ! !)
注意 this() 必须放在第一行,且只能在构造方法中
第一种 this.data 调用当前对象的属性
class Person {
private String name;
private int age;
public String getName() {
return name;// 这里其实也是可以 加 this 不影响
}
public void setName(String name) {
this.name = name;
这里 就是 调用当前对象的属性,要不然就会自己赋值自己
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
这里 就是 调用当前对象的属性,要不然就会自己赋值自己
如果不加 age 就 为 0
}
}
public class Main {
public static void main(String[] args) {
}
}
第二种 this.func 调用当前对象的方法
class Person {
private String name;
private int age;
public void eat() {
System.out.println(name+"正在吃饭!");
}
private void print() {
this.eat(); 调用当前对象的方法 但是 在静态方法中不要去调用普通方法因为没对象
System.out.println("姓名:"+name+" 年龄:"+age);
}
}
public class Main {
public static void main(String[] args) {
}
}
第三种 this() 调用当前对象的其他构造方法(存放在构造函数当中 ! ! !)
class Person {
private String name;
private int 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 Person() {
this("laoba"); 调用带有一个参数的构造方法 先打印 带有一个参数的
在打印 不带参数的
注意 this() 必须放在 第一行 ,不能放 2个或 多个 this()
System.out.println("Person():: 不带参数的构造方法 ");
}
public Person(String name) {
this.name = name;
System.out.println("带一个参数的构造方法");
}
public Person(String name,int age) {
System.out.println("带两个参数的构造方法");
}
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
}
6.代码块
class Person {
private String name;
private int age;
static int count;
{
System.out.println("实例代码块!");
实例代码块优先于构造函数执行
}
static {
System.out.println("静态代码块!");
静态代码块不管生成多少个对象,其只会执行一次,且最先执行的
静态代码块执行完毕后,实例代码块执行,再然后是构造函数执行
}
}
public class Main{
public static void main(String[] args) {
本地代码块 定义在方法中的代码块(这种用法较少见/.)
{
}
}
}
class Person {
private String name;
private int age;
public Person() {
System.out.println( "Person()::不带参数的构造方法");
} 这里 我们将 构造方法放在最前 ,结果 打印 还是 先从 静态代码块,然后实例代码块,最后 构造方法
{
System.out.println("实例代码块!");
}
static {
System.out.println("静态代码块!");
}
}
// 问题 代码块是怎么被调用的
public class Main{
public static void main(String[] args) {
Person person = new Person();
这里我们在new一个对象
System.out.println("=====================");
Person person2 = new Person();
观察 结果,发现 此时 只打印了 实例代码块 和 构造方法 内的 内容
结论 静态代码块 只被 执行了一次 更你 new 多少 对象 无关系
}
}
这里我们 继续
class Person {
private String name;
private int age = 19;
public static int count; 第一次打印时的count
public static int count = 10;
public Person() {
System.out.println( "Person()::不带参数的构造方法");
}
{
this.age = 99;
System.out.println("实例代码块!");
}
static {
count = 99;
System.out.println("静态代码块!");
}
那么 将 count = 10 放到这里呢
public static int count = 10;
未初始化的count 放在这里
public static int count;
此时的值是多少?
}
// 问题 代码块是怎么被调用的
public class Main{
public static void main(String[] args) {
System.out.println(Person.count);
打印出来
System.out.println(Person.count);
此时count 打印的是 10 还是 99 ?
将 count = 10 定义到 静态代码块下面
System.out.println(Person.count);
此时count 打印的是 10 还是 99 ?
最后一问 将 count 不初始化放在 静态代码块后面呢?
}
}
最后的 4个问题 只是让大家看看, 只要知道 先执行静态在执行 实例,最后执行函数方法就行。
最后小练习
1.编写一个类Calculator,有两个属性num1,num2,这两个数据的值,不能在定义的同时初始化,最后实现加减乘
除四种运算
class Calculator {
private int num1;
private int num2;
public int getNum1() {
return num1;
}
public void setNum1(int num1) {
this.num1 = num1;
}
public int getNum2() {
return num2;
}
public void setNum2(int num2) {
this.num2 = num2;
}
public int add() {
return num1 + num2;
}
public int sub() {
return num1 - num2;
}
public int mul() {
return num1 * num2;
}
public double dev() {
return num1 * 1.0 / num2;
}
}
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator();
calculator.setNum1(1);
calculator.setNum2(2);
System.out.println(calculator.add());
}
}
2.实现两个变量值得交换
class Person {
public int num;
}
public class Main {
// 这里 num1 ,numw 为 栈区重新 创建的引用,
// 传参传进来了person1,person2 在堆区对象的地址
public static void swap(Person num1,Person num2) {
int tmp = num1.num;
num1.num = num2.num;
num2.num = tmp;
}
public static void main(String[] args) {
Person person1 = new Person();
person1.num = 10;
Person person2 = new Person();
person2.num = 20;
System.out.println(person1.num+" "+person2.num);
swap(person1,person2);
System.out.println(person1.num+" "+person2.num);
}
}
最后你懂的



