一、类与对象的初步认知
C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
JAVA是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
面向过程注重的是过程,在整个过程中所涉及的行为,就是功能。
面向对象注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来
1.1、面向对象概念
1.面向对象是思考问题的一种思考方式,是一种思想。 2.类就是一类对象的统称。对象就是这一类具体化的一个实例。 3.面向对象的好处:将复杂的事情变简单了,只要面对一个对象就行。
1.2、面向对象设计
面向对象设计把握一个重要的经验:谁拥有数据,谁对外提供操作这些数据(私有)的方法! (被动的一方是数据的拥有者,主动的一方是执行者) 开发时:找对象,建对象,用对象,并维护对象之间的关系。
面向对象就是用代码(类)来描述客观世界的事物的一种方式. 一个类主要包含一个事物的属性和行为
以上转载于:https://blog.csdn.net/DarkAndGrey/article/details/121039002
二、类和类的实例化
类就是一类对象的统称。对象就是这一类具体化的一个实例。
简单的例子:我们做月饼的模子就是一个类,而通过这个模子可以做出月饼,那么在这个例子当中,类就是那个模子,而月饼就是那个对象,所以月饼就是一个实体。一个模子可以实例化无数个对象。
总的来说:类相当于一个模板,对象是由模板产生的样本。一个类,可以产生无数的对象。
声明一个类就是创建一个新的数据类型,而类在 Java 中属于引用类型, Java 使用关键字 class 来声明类。
2.1、类的创建
基本语法
// 创建类
class <class_name>{
field;//成员属性,也叫字段,成员变量
method;//成员方法
}
// 实例化对象
<class_name> <对象名> = new <class_name>();
class为定义类的关键字,ClassName为类的名字,{}中为类的主体(类体)。
类中的元素称为:成员属性(成员变量)。类中的函数称为:成员方法。
例如:创建一个学生类
//创建一个学生类
class Student{
//学生有的属性
String name; //姓名
int age; //年龄
int hight; //身高
//方法(又称 成员方法) 可以解析为 学生的行为
public void eat(){
System.out.println(name + " 正在吃饭!");
}
public void sleep(){
System.out.println(name + " 正在睡觉!");
}
}
和之前写的方法不同, 此处写的方法不带 static 关键字. 后面我们会详细解释 static 是干啥的
2.2、类的实例化 (通过new关键字)
// 创建类
class <class_name>{
field;//成员属性,也叫字段,成员变量
method;//成员方法
}
// 实例化对象
<class_name> <对象名> = new <class_name>();
用类类型创建对象的过程,称为类的实例化
- 类只是一个模型一样的东西,限定了类有哪些成员.
- 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
- 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东
西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
//创建一个学生类
class Student{
//学生有的属性
String name; //姓名
int age; //年龄
int hight; //身高
//方法,这个方法指的是能完成的功能,行为
public void eat(){
System.out.println(name + " 正在吃饭!");
}
public void sleep(){
System.out.println(name + " 正在睡觉!");
}
}
public class TestDome {
public static void main(String[] args) {
Student student1 = new Student();
}
}
一个类可以实例化多个对象
//创建一个学生类
class Student{
//学生有的属性
String name; //姓名
int age; //年龄
int hight; //身高
//方法,这个方法指的是能完成的功能,行为
public void eat(){
System.out.println(name + " 正在吃饭!");
}
public void sleep(){
System.out.println(name + " 正在睡觉!");
}
}
public class TestDome {
public static void main(String[] args) {
Student student1 = new Student();
Student student2 = new Student();
Student student3 = new Student();
Student student4 = new Student();
}
2.3、访问 类的成员变量(通过引用来访问)
//创建一个学生类
class Student{
//学生有的属性
String name; //姓名
int age; //年龄
int hight; //身高
//方法,这个方法指的是能完成的功能,行为
public void eat(){
System.out.println(name + " 正在吃饭!");
}
public void sleep(){
System.out.println(name + " 正在睡觉!");
}
}
public class TestDome {
public static void main(String[] args) {
Student student = new Student();
//访问属性
System.out.println(student.name);
System.out.println(student.age);
System.out.println(student.hight);
//访问方法
student.eat();
student.sleep();
//还可以给 属性赋值
student.name = "张三";
student.age = 18;
System.out.println(student.name);
System.out.println(student.age);
}
}
可以看见上面的属性没有初始化的时候是有默认值的
三、类的成员
类的成员可以包含以下:字段、方法、代码块、内部类和接口等
3.1、字段/属性/成员变量
定义在类的内部,方法的外部定义的变量. 这样的变量我们称为 “字段” 或 “属性” 或 “成员变量”(三种称呼都可以, 一般不会严格区分)
//创建一个学生类
class Student{
//字段,属性,成员变量
String name; //姓名
int age; //年龄
int hight; //身高
//方法,这个方法指的是能完成的功能,行为
public void eat(){
System.out.println(name + " 正在吃饭!");
}
public void sleep(){
System.out.println(name + " 正在睡觉!");
}
}
注意事项
使用 . 访问对象的字段.
“访问” 既包含读, 也包含写.
对于一个对象的字段如果没有显式设置初始值, 那么会被设置一个默认的初值
3.1.1、成员变量又可分为两类: 普通成员变量,静态成员变量
成员变量又可分为两类: 普通成员变量,静态成员变量
静态成员变量就是由static修饰的变量
class Person{
//普通成员变量
public String name; //姓名
public int age; //年龄
//静态成员变量
public static int cont;
}
3.1.1.1、普通成员变量,静态成员变量的区别
首先看一段代码:
class Person{
//普通成员变量
public String name; //姓名
public int age; //年龄
//静态成员变量
public static int cont;
//方法,这个方法指的是能完成的功能,行为
public void eat(){
System.out.println(name + " 正在吃饭!");
}
public void sleep(){
System.out.println(name + " 正在睡觉!");
}
}
public class TestDome {
public static void main(String[] args) {
Person person1 = new Person();
person1.age++;
System.out.println(person1.age);
System.out.println("=========");
Person person2 = new Person();
person2.age++;
System.out.println(person2.age);
}
}
此时再看代码:
class Person{
//普通成员变量
public String name; //姓名
public int age; //年龄
//静态成员变量
public static int cont;
//方法,这个方法指的是能完成的功能,行为
public void eat(){
System.out.println(name + " 正在吃饭!");
}
public void sleep(){
System.out.println(name + " 正在睡觉!");
}
}
public class TestDome {
public static void main(String[] args) {
Person person1 = new Person();
person1.age++;
person1.cont++;
System.out.println(person1.age);
System.out.println("cont = " + person1.cont);
System.out.println("=========");
Person person2 = new Person();
person2.age++;
person2.cont++;
System.out.println(person2.age);
System.out.println("cont = " + person2.cont);
}
}
静态成员变量/方法,就是类变量,它只属于类,不属于对象,可以通过 类名.静态成员变量/方法 的方式来访问
class Person{
//普通成员变量
public String name; //姓名
public int age; //年龄
//静态成员变量
public static int cont;
//方法,这个方法指的是能完成的功能,行为
public void eat(){
System.out.println(name + " 正在吃饭!");
}
public void sleep(){
System.out.println(name + " 正在睡觉!");
}
public static void func(){
System.out.println("static :: func");
}
}
public class TestDome {
public static void main(String[] args) {
Person.cont = 10;
System.out.println(Person.cont);
Person.func();
}
}
3.1.1.2、普通方法里面能不能定义 静态成员变量
普通方法里面不能定义静态成员变量
但是能调用静态成员方法
3.1.1.3、静态方法里面能不能定义 静态成员变量
无论是 普通成员方法还是静态成员方法,都不能在其内部创建一个被static修饰的变量
因为 被static修饰了的变量,该变量就属于类了(类变量/静态变量)。
而你把一个(类变量/静态成员变量)写在方法里,就意味着属于方法(是一个局部变量,不再是 类变量了),而不属于类
所以冲突了,不合适,导致编译器报错
3.1.1.4、总结
1、static定义的变量,类变量,属于类的
2、eat方法的调用,需要对应的引用来调用。
3、静态方法是不需要对象的,直接就可以用类来调用,如果静态方法里面有静态变量,那这个变量就是属于方法的,不是属于类的了,这就有冲突了
4、当然如果在普通方法里面定义静态变量,那这个变量也属于方法,而不属于类了
5、静态的变量是不能在方法中定义的
6、静态的方法不能调用普通方法
7、静态的方法能调用静态方法
8、普通方法可以调用普通方法
9、普通方法可以调用静态方法
3.1.1.5、一个dan疼的面试题
main 函数为什么是静态的?
首先 main 函数 是不是静态都可以!!!
这个东西取决于 JVM 的规则。
main 之所以 是 静态的,是因为 在设计 JVM的时候,就这么设计的
所以 main 只有被static 修饰的时候,JVM才认为它是main函数
3.1.2、引用 一定是在栈上吗?
答:不一定
class Person{
public String name = "author";
public void eat(){
staticFunc();
System.out.println(name+"正在吃饭.");
}
public static void staticFunc(){
System.out.println("static::func()");
}
}
public class TestDome {
Person person = new Person();
public static void main(String[] args) {
TestDome classAndObject = new TestDome();
}
}
3.2、static 关键字
1、修饰属性
修饰属性,Java静态属性和类相关, 和具体的实例无关. 换句话说, 同一个类的不同实例共用同一个静态属性2、修饰方法
如果在任何方法上应用 static 关键字,此方法称为静态方法。
静态方法属于类,而不属于类的对象。
可以直接调用静态方法,而无需创建类的实例。
静态方法可以访问静态数据成员,并可以更改静态数据成员的值。
注意事项1:
静态方法和实例无关, 而是和类相关. 因此这导致了两个情况:
静态方法不能直接使用非静态数据成员或调用非静态方法(非静态数据成员和方法都是和实例相关的).
this和super两个关键字不能在静态上下文中使用(this 是当前实例的引用, super是当前实例父类实例的引用, 也是和当前实例相关).
注意事项2
我们曾经写的方法为了简单, 都统一加上了 static. 但实际上一个方法具体要不要带 static, 都需要是情形而定. main 方法为 static 方法
3.3、小结
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 TestDome {
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();
}
}
3.4、认识null
null 在 Java 中为 “空引用”, 表示不引用任何对象. 类似于 C 语言中的空指针. 如果对 null 进行 . 操作就会引发异常.
class Person{
public String name = "author";
public void eat(){
staticFunc();
System.out.println(name+"正在吃饭.");
}
public static void staticFunc(){
System.out.println("static::func()");
}
}
public class TestDome {
public static void main(String[] args) {
Person person = null;
System.out.println(person.name);
}
}
四、封装 pritave
什么叫封装?
- <<代码大全>> 开篇就在讨论一个问题: 软件开发的本质就是对程序复杂程度的管理. 如果一个软件代码复杂程度太高, 那么就无法继续维护. 如何管理复杂程度? 封装就是最基本的方法.
- 在我们写代码的时候经常会涉及两种角色: 类的实现者和类的调用者.
- 封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就行了.
- 这样就降低了类使用者的学习和使用成本, 从而降低了复杂程度
4.1、如何打印对象的属性
class Person{
public String name = "author";
public void eat(){
staticFunc();
System.out.println(name+"正在吃饭.");
}
public static void staticFunc(){
System.out.println("static::func()");
}
public String toString(){
return "张三";
}
}
public class TestDome {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
}
- toString 方法会在 println 的时候被自动调用.
- 将对象转成字符串这样的操作我们称为序列化(把一个对象转换成字符串). 反序列化(把字符串转换成对象)
- toString 是 Object 类提供的方法, 我们自己创建的 Person 类默认继承自 Object 类, 可以重写 toString 方法
4.1.1、如何快速实现toString方法
4.2、private实现封装
- private/ public 这两个关键字表示 “访问权限控制” .
- 被 public 修饰的成员变量或者成员方法, 可以直接被类的调用者使用.
- 被 private 修饰的成员变量或者成员方法, 不能被类的调用者使用.
- 换句话说, 类的使用者根本不需要知道, 也不需要关注一个类都有哪些 private 的成员. 从而让类调用者以更低的成本来使用类.
注意事项
- private 不光能修饰字段, 也能修饰方法
- 通常情况下我们会把字段设为 private 属性, 但是方法是否需要设为 public,
就需要视具体情形而定. 一般我们希 望一个类只提供 “必要的” public 方法, 而不应该是把所有的方法都无脑设为 public.
4.3、getter和setter方法
- 使用private修饰的属性,在类的外面是不能被访问的
- 所以就可以使用getter和setter方法,来访问
- getter 方法:用来访问属性
- setter 方法:用来给属性赋值,修改
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 void eat(){
staticFunc();
System.out.println(name+"正在吃饭.");
}
public static void staticFunc(){
System.out.println("static::func()");
}
}
public class TestDome {
public static void main(String[] args) {
Person person = new Person();
//给属性赋值
person.setAge(18);
person.setName("张三");
System.out.println(person.getAge());
System.out.println(person.getName());
}
}
- 当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值. this 表示当前实例的引用
注意事项
- getName 即为 getter 方法, 表示获取这个成员的值.
- setName 即为 setter 方法, 表示设置这个成员的值
- 当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值. this 表示当前实例的引用.
- 不是所有的字段都一定要提供 setter / getter 方法, 而是要根据实际情况决定提供哪种方法.
- 在 IDEA 中可以使用 alt + insert (或者 alt + F12) 快速生成 setter / getter 方法. 在 VSCode 中可以使用鼠标右键
菜单 -> 源代码操作 中自动生成 setter / getter 方法
五、构造方法
5.1、什么是构造方法
- 构造方法:方法名和类名相同,并且没有返回值
- 构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用, 用于完成初始化操作
class Person{
public String name;
public int age;
public Person(){
//这就是构造方法
}
public void eat(){
System.out.println("姓名:" + name);
}
}
5.2、基本语法
new 执行过程(对象如何产生)
- 为对象分配内存空间
- 调用对象的构造方法
语法规则
- 方法名称必须与类名称相同
- 构造方法没有返回值类型声明
- 调用合适的构造方法,每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造,说明构造方法不止一个)
注意事项
- 如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数
- 若类中定义了构造方法,则默认的无参构造将不再生成.
- 构造方法支持重载. 规则和普通方法的重载一致
class Person{
public String name;
public int age;
public Person(){
//没有一个参数的构造方法构造方法
System.out.println("没有参数的构造方法构造方法");
}
public Person(int age){
//带有一个参数的构造方法构造方法
System.out.println("带有一个参数的构造方法构造方法");
}
public Person(int age, String name){
//带有两个参数的构造方法构造方法
System.out.println("带有两个参数的构造方法构造方法");
}
public void eat(){
System.out.println("姓名:" + name);
}
}
public class TestDome {
public static void main(String[] args) {
Person person1 = new Person();
Person person2 = new Person(18);
Person person3 = new Person(18,"张三");
}
}
5.3、this关键字(面试题)
this表示当前对象引用(注意不是当前对象). 可以借助 this 来访问对象的字段和方法
this关键字的用法
1、this.data 调用当前对象的属性
2、this.func() 调用当前对象的方法
3、this() 调用对象的其他构造方法
5.3.1、this调用当前的方法
class Person{
public String name;
public int age;
public Person(){
//没有一个参数的构造方法构造方法
System.out.println("没有参数的构造方法构造方法");
}
public Person(int age){
//带有一个参数的构造方法构造方法
//this调用属性
this.age = age;
System.out.println("带有一个参数的构造方法构造方法");
}
public Person(int age, String name){
this.age = age;
this.name = name;
this.eat();
//带有两个参数的构造方法构造方法
System.out.println("带有两个参数的构造方法构造方法");
}
public void eat(){
System.out.println("姓名:" + name);
}
}
public class TestDome {
public static void main(String[] args) {
Person person = new Person(18, "张三");
}
}
5.3.2、this调用对象的其他的构造方法
class Person{
public String name;
public int age;
public Person(){
//没有一个参数的构造方法构造方法
System.out.println("没有参数的构造方法构造方法");
}
public Person(int age){
//带有一个参数的构造方法构造方法
//this调用属性
this(18,"张三");
this.age = age;
System.out.println("带有一个参数的构造方法构造方法");
}
public Person(int age, String name){
this.age = age;
this.name = name;
this.eat();
//带有两个参数的构造方法构造方法
System.out.println("带有两个参数的构造方法构造方法");
}
public void eat(){
System.out.println("姓名:" + name);
}
}
public class TestDome {
public static void main(String[] args) {
Person person = new Person(18);
}
}
六、认识代码块
6.1、什么是代码块
使用 {} 定义的一段代码.
根据代码块定义的位置以及关键字,又可分为以下四种:
- 普通代码块
- 构造块/实例代码块
- 静态块
- 同步代码块(后续讲解多线程部分再谈)
- 普通代码块:定义在方法中的代码块
- 构造块/实例代码块:定义在类中的代码块(不加修饰符)。也叫:实例代码块。构造代码块一般用于初始化实例成员变量
- 静态块:使用static定义的代码块。一般用于初始化静态成员属性。
class Person{
public String name;
public int age;
{
System.out.println("实例代码块");
}
static {
System.out.println("静态代码块");
}
public Person(){
//没有一个参数的构造方法构造方法
System.out.println("没有参数的构造方法构造方法");
}
public Person(int age){
//带有一个参数的构造方法构造方法
//this调用属性
this.age = age;
System.out.println("带有一个参数的构造方法构造方法");
}
public Person(int age, String name){
this.age = age;
this.name = name;
this.eat();
//带有两个参数的构造方法构造方法
System.out.println("带有两个参数的构造方法构造方法");
}
public void eat(){
{
System.out.println("普通代码块");
}
System.out.println("姓名:" + name);
}
}
public class TestDome {
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("==============");
Person person2 = new Person();
}
}
- 1、在new对象的时候,首先执行静态代码块,然后执行实例代码块,最后调用构造方法
- 2、不管new多少个对象,静态代码块只执行1次
七、匿名对象
匿名只是表示没有名字的对象.
- 没有引用的对象称为匿名对象.
- 匿名对象只能在创建对象时使用.
- 如果一个对象只是用一次, 后面不需要用了, 可以考虑使用匿名对象
class PersonA{
public String name;
public void eat(){
System.out.println(name + "正在吃饭");
}
}
public class TestDome {
public static void main(String[] args) {
System.out.println(new PersonA().name);
new PersonA().eat();
System.out.println(new PersonA());
System.out.println("================");
// 正确写法
PersonA persona = new PersonA();
System.out.println(persona.name);
persona.eat();
System.out.println(persona);
}
}