目录
一、类与对象的初步认知
二、类与类的实例化
1、类的基本语法
2、类的实例化
3、类的成员
3.1、成员变量/属性
3.2、认识null
3.3、方法
三、构造方法
四、关键字
1、this 关键字
(1)通过this关键字调用成员变量
(2)通过this关键字调用成员方法
(3)this关键字调用构造方法
2、static 关键字
(1)修饰属性
(2)修饰方法
五、类的封装
1.如何实现封装
2.getter和setter方法
六、代码块
1、普通代码块
2、构造代码块
3、静态代码块
七、toString方法
八、匿名对象
九、结尾 小试牛刀
一、类与对象的初步认知
C语言是
面向过程
的,
关注
的是
过程
,分析出求解问题的步骤,通过函数调用逐步解决问题。
JAVA是
基于面向对象
的,
关注
的是
对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。
面向过程注重的是过程,在整个过程中所涉及的行为,就是功能。
面向对象注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来 。
面向对象的特点可以概括为:
封装、
继承、
多态。
后文我们会介绍封装以及继承的使用,多态之后会开一篇详细讲。
二、类与类的实例化
类就是一类对象的统称。对象就是这一类具体化的一个实例。
总的来说:类相当于一个模板,对象是由模板产生的样本。一个类,可以产生无数的对象。
声明一个类就是创建一个新的数据类型,而类在
Java
中属于
引用类型
,
Java
使用关键字
class
来声明类。
下面我们来简单的声明一个类:
1、类的基本语法
class
<
class_name
>
{
field
;
//
成员属性
method
;
//
成员方法
}
//
实例化对象
<
class_name
> <
对象名
> =
new
<
class_name
>
();
class
为定义类的关键字,
class_name
为类的名字,{ }
中为类的主体。
类中的元素称为:成员属性;类中的函数称为:成员方法。
如下一个完整的类:
class Person {
public int age;//成员属性
public String name;
public String sex;
public void eat() {//成员方法
System.out.println("吃饭!");
}
public void sleep() {
System.out.println("睡觉!");
}
}
2、类的实例化
用类型创建对象的过程,称为类的实例化。
1. 类只是一个
模型
一样的东西,指定了类有哪些成员。
1、类的基本语法
class
<
class_name
>
{
field
;
//
成员属性
method
;
//
成员方法
}
//
实例化对象
<
class_name
> <
对象名
> =
new
<
class_name
>
();
class
为定义类的关键字,
class_name
为类的名字,{ }
中为类的主体。
类中的元素称为:成员属性;类中的函数称为:成员方法。
如下一个完整的类:
class Person {
public int age;//成员属性
public String name;
public String sex;
public void eat() {//成员方法
System.out.println("吃饭!");
}
public void sleep() {
System.out.println("睡觉!");
}
}
2、类的实例化
用类型创建对象的过程,称为类的实例化。
1. 类只是一个
模型
一样的东西,指定了类有哪些成员。
2. 一个类可以实例化出多个对象,实例化出的对象才占用实际的物理空间,存储类成员变量。
(类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东 西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间)下面我们通过上一个例题的类来实例化一个对象:
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(); //通过new实例化对象
person.eat(); //成员方法调用需要通过对象的引用调用
person.sleep();
Person person2 = new Person();
Person person3 = new Person();
}
}
//运行结果
吃饭!
睡觉!
3、类的成员
3.1、成员变量/属性
在类中
,
但是方法外部定义的变量
。
这样的变量我们称为
"
属性
"
或
"
成员变量"。
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
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(float与double默认为0.0)
- 对于 boolean 类型, 默认值为 false
- 对于 char 类型,默认为空字符,'u0000'
- 对于引用类型(String, Array, 以及自定义类), 默认值为 null
3.2、认识null
null
在
Java
中为
"
空引用
",
表示不引用任何对象
。
类似于
C
语言中的空指针
。
如果对
null
进行操作就会引发空指针异常。(
NullPointerException
)
3.3、方法
方法经常用于描述一个对象的行为。例:
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();
}
}
// 执行结果
我叫张三, 今年18岁
方法中还有一种特殊的方法称为
构造方法 。
在实例化对象的时候会被自动调用到的方法,
方法名字和类名相同,
用于对象的初始化。
三、构造方法
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();
}
}
// 执行结果
我叫张三, 今年18岁
方法中还有一种特殊的方法称为
构造方法 。
在实例化对象的时候会被自动调用到的方法,
方法名字和类名相同,
用于对象的初始化。
三、构造方法
基本语法:
构造方法是一种特殊方法,使用关键字new实例化新对象时会被自动调用,用于完成初始化操作。
注意: 1.方法名称必须与类名称相同。 2. 构造方法没有返回值类型声明。 3. 每一个类中一定至少存在一个构造方法(如果没有明确定义,则系统会自动生成一个无参构造方法,这个默认生成的构造方法不仅没有参数,在方法体重也没有任何的代码,即什么也不做。若咱们已经定义了一个构造方法,则系统不会再自动生成默认的构造方法) 4.在方法中不能使用 return 语句返回一个值,但是可以单独写 return 语句来作为方法的结束。 5.构造方法支持重载,规则与普通方法的重载一致。(前前篇有详细写普通方法重载) 看个例子感受一下:class Person {
private String name;//成员变量
private int age;
private String sex;
//默认无参的构造函数
public Person() {
this.name = "caocao";
this.age = 10;
this.sex = "男";
}
//带有3个参数的构造函数
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 p1 = new Person();//调用不带参数的构造函数 如果程序没有提供会调用不带参数的构造函数
p1.show();
Person p2 = new Person("zhangfei",80,"男");//调用带有3个参数的构造函数
p2.show();
}
}
// 执行结果
name: caocao age: 10 sex: 男
name: zhangfei age: 80 sex: 男
四、关键字
1、this 关键字
this指代当前对象,用于在方法中访问对象的其他成员。接下来讲讲this关键字在程序中 3 种常见的用法。
(1)通过this关键字调用成员变量
解决与局部变量名称冲突问题。
看个例子:
class Person{
int age; //成员变量age
public Person(int age){ //局部变量age
this.age=age; //将局部变量age的值赋给成员变量age
}
}
(1)通过this关键字调用成员变量
解决与局部变量名称冲突问题。
看个例子:
class Person{
int age; //成员变量age
public Person(int age){ //局部变量age
this.age=age; //将局部变量age的值赋给成员变量age
}
}
如上例——如果在构造方法中使用“age”则访问的是局部变量,如果使用“this.age”则访问的是成员变量。
(2)通过this关键字调用成员方法
如下:
class Person{
public void openMouth(){
....
}
public void speak(){
this.openMouth();
}
}
通过上述例子我们使用this关键字调用了openMouth()方法。需要注意的是此处的this关键字可以省略不写,效果一样。因此不再赘述,只是表示可以这样调用。
(3)this关键字调用构造方法
构造方法是在实例化对象时被Java虚拟机自动调用的,在程序中可以在一个构造方法中使用“this[参数1,参数2,...]”的形式来调用其他的构造方法。
class Person{
public Person(){
System.out.println("无参的构造方法被调用了...");
}
public Person(int age){
this();
System.out.println("有参的构造方法被调用了...");
}
}
public class testdemo{
public static void main(String[] args){
Person p=new Person(18);
}
}
//运行结果
无参的构造方法被调用了...
有参的构造方法被调用了...
分析一下上述代码:实例化Person对象时,调用了有参的构造方法,在有参的构造方法中又通过this()调用了无参的构造函数,因此运行结果中显示两个构造方法都被调用了。
在使用this调用类的构造方法时,应注意以下几点:
1、只能在构造方法中使用 this 调用其他的构造方法,不能在其他成员方法中使用。
2、在构造方法中,使用 this 调用构造方法的语句必须是该方法的第一条执行语句,且只能出现一次。
2、static 关键字
首先,static 关键字可以用来 ——
1、修饰属性 2、修饰方法 3、代码块 4、修饰类(后面讲内部类会讲到,预估下一篇 )(1)修饰属性
Java静态属性和类相关,和具体的实例无关。 换句话说,同一个类的不同实例可以共用同一个静态属性。
当属性被static修饰时,为所有类共享。且不属于对象,访问方式为:类名.属性。
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
注意:
1、static 关键字只能用于修饰成员变量,不能用于修饰局部变量(即不能在非静态方法里声明一个变量为 static),否则编译会报错!
为什么呢?因为 static 修饰的变量,任何一个类的实例化对象都可以访问,而方法中声明的变量都是局部的,方法执行完后就要销毁,释放空间的。
(2)修饰方法
如果在任何方法上应用
static
关键字,此方法称为静态方法。
注意:
a、可以直接调用静态方法(类名.静态方法名),而无需创建类的实例。
b、静态方法可以访问静态数据成员,并可以更改静态数据成员的值。
光说还是有点抽象,上个例子:
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、静态方法不能直接使用非静态数据成员或调用非静态方法。(因为非静态数据成员和方法都是和实例相关的)。
2、this 和 super 两个关键字不能在静态上下文中使用 (this 是当前对象的引用 ,super 是当前对象父类对象的引用 ,都与 当前对象相关) (3)数据属性的内存布局: 例如 下列一个程序代码——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
其在内存中分布如下:
由上图我们可知:
Java 有栈内存和堆内存。其中栈内存用于存放基本类型的变量(局部变量)和对象的引用变量(例如本例中的 t1与 t2 ),堆内存用于存放由new创建的对象(例如本例成员变量a)和数组。
但是静态变量(本例中的count),编译时已经产生,属于类本身,且只有一份。是存放在方法区的。
五、类的封装
1.如何实现封装
类的封装,是指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象的内部信息,而是通过该类所提供的方法来实现对内部信息的访问操作。
它的具体实现过程是,将类中的属性私有化,即使用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();
}
}
// 执行结果
我叫张三, 今年18岁
- 此时字段已经使用 private 来修饰。类的调用者不能直接使用,而需要借助 show 方法。此时类的使用者就不必了解 Person 类的实现细节。
- 同时如果类的实现者修改了成员变量的名字,类的调用者不需要做出任何修改(因为类的调用者根本访问不到 name, age 这样的变量),这样代码维护成本大大降低。
2.getter和setter方法
当我们使用 private 来修饰字段的时候, 就无法直接使用这个字段了。此时如果需要获取或者修改这个 private 属性, 就需要使用 getter / setter 方法。
class Person {
private String name; //实例成员变量
private int age;
public void setName(String name){
this.name = name;
}
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("caocao");
String name = person.getName();
System.out.println(name);
person.show();
}
// 运行结果
caocao
name: caocao age: 0
快捷键:
在
IDEA
中可以使用
alt + insert (
或者
alt + F12)
快速生成
setter / getter 方法。
在
VSCode
中可以使用鼠标右键 -> 菜单 ->
源代码操作中自动生成
setter / getter
方法。
六、代码块
使用
{ }
定义的一段代码
.
根据代码块定义的位置以及关键字,又可分为以下三种:
- 普通代码块
- 构造块
- 静态块
1、普通代码块
普通代码块为:定义在方法中的代码块。
public class Main{
public static void main(String[] args) {
{
int x = 10 ; //直接使用{}定义,普通方法块
System.out.println("x1 = " +x);
}
int x = 100 ;
System.out.println("x2 = " +x);
}
}
// 执行结果
x1 = 10
x2 = 100
2、构造代码块
构造代码块:定义在类中的代码块
(
不加修饰符
)
。也叫:
实例代码块
。构造代码块一般用于初始化实例成员变量。
class Person{
private String name; //实例成员变量
private int age;
private String sex;
public Person() {
System.out.println("I am Person init()!");
}
//实例代码块(也叫构造代码块)
{
this.name = "张三";
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);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
p1.show();
}
}
// 运行结果
I am instance init()!
I am Person init()!
name: 张三 age: 12 sex: man
由上例可得——实例代码块优先于构造函数执行。
3、静态代码块
使用
static
定义的代码块。
一般用于初始化静态成员属性。
class Person{
private String name; //实例成员变量
private int age;
private String sex;
private static int count = 0;//静态成员变量 由类共享数据 存放于在方法区
public Person(){
System.out.println("执行构造函数!");
}
//实例代码块
{
this.name = "张三";
this.age = 12;
this.sex = "man";
System.out.println("执行实例代码块!");
}
//静态代码块
static {
count = 10; //只能访问静态数据成员
System.out.println("执行静态代码块!");
}
public void show(){
System.out.println("name: "+name+" age: "+age+" sex: "+sex);
}
}
public class Main {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person();
p2.show();
}
}
//运行结果
执行静态代码块!
执行实例代码块!
执行构造函数!
执行实例代码块!
执行构造函数!
name: 张三 age: 12 sex: man
由上例,我们可以得出:
1、不管生成多少个对象,静态代码块只会执行一次,且是最先执行的。
2、静态、实例、构造函数如果都存在,则执行顺序为:静态代码块>实例代码块>构造函数。
七、toString方法
我们先来看一段示例代码:
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 Main {
public static void main(String[] args) {
Person person = new Person("haha",19);
System.out.println(person);
}
}
// 执行结果
Person@1c168e5
我们发现这里打印的是一个地址的哈希值,原因:调用的是Object的toString方法。这个方法将对象的内存地址进行哈希运算,返回一个int类型的哈希值。
而在实际开发中,我们通常希望toString()方法返回的不仅仅是对象的基本信息,而是一些更有用的信息,因此我们可以通过重写toString()方法来实现。
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);
}
//重写Object的toString方法
@Override
public String toString() {
return "Person{" +
"name='" + name + ''' +
", age=" + age +
'}';
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person("haha",19);
System.out.println(person);
}
}
// 执行结果
Person{name='haha', age=19}
总结:
1、toString
方法会在
println
的时候被自动调用。
2、将对象转成字符串这样的操作我们称为
序列化。
3、toString
是
Object
类提供的方法
,
我们自己创建的
Person
类默认继承自
Object
类(Java中提供了一个object类,它是所有类的父亲,每个类都直接或间接继承自此类)
, 因此我们
可以重写
toString
方法实现我们自己版本的转换字符串方法。(
关于继承和重写这样的概念
,
下一篇再详细讲
)
4、@Override
在
Java
中称为
"
注解
",
此处的
@Override
表示下面实现的
toString
方法是重写了父类的方法
。
关于注解后面的课程会详细介绍。
5、IDEA
快速生成
Object
的
toString
方法快捷键:
alt+f12(insert)
或者 右键单击 选择Generate》toString()》选择所需生成的成员即可。(如果还不清楚可以参考下图步骤)
》》
》》
八、匿名对象
匿名只是表示没有名字(没有引用)的对象。
匿名对象只能在创建对象时使用。
如果一个对象只是用一次
,
后面不需要用了
,
可以考虑使用匿名对象。
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 Main {
public static void main(String[] args) {
new Person("张三",19).show(); //通过匿名对象调用方法
}
}
// 执行结果
name:张三 age:19
九、结尾 小试牛刀
学了上述知识后,咱们拿个小题目结尾~大家也可以动手敲敲代码。
题目:实现交换两个变量的值。要求:需要交换实参的值(不要那种假性交换)
想好再看哦
3
2
1
下面公布答案——
class MyValue {
public int val;
}
public class Main {
public static void swap(MyValue myV1,MyValue myV2) {
int tmp = myV1.val;
myV1.val = myV2.val;
myV2.val = tmp;
}
public static void main(String[] args) {
MyValue myValue1 = new MyValue();
myValue1.val = 10;
MyValue myValue2 = new MyValue();
myValue2.val = 20;
swap(myValue1,myValue2);
System.out.println("myValue1:"+myValue1.val+";" +"myValue2:"+myValue2.val);
}
}
//运行结果
myValue1:20;myValue2:10
有同学可能不理解,好像这种写法跟之前传值没什么变化呀?实际上,我们这个传的是引用。画个图就更好理解了。
这节就结束啦,下节再见~
to be continue →
欢迎大家互相探讨交流补充 欢迎捉虫!



