Java-类和对象
Posted ViolentAsteroid
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java-类和对象相关的知识,希望对你有一定的参考价值。
目录
一.类和对象的初步认知
1.面向过程和面向对象
面向过程:C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题
面向对象:JAVA是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成
面向过程:注重的是过程,在整个过程中所涉及的行为,就是功能。
面向对象:注重的是对象,也就是参与过程所涉及到的主体。是通过逻辑将一个个功能实现连接起来
举个例子: 这里把衣服放进洗衣机、启动洗衣机和将衣服拿出洗衣机都是对洗衣机的操作。这里洗衣机就是一个对象,洗衣机洗衣服的功能就包含在这个对象中。
2.面向对象设计
面向对象设计把握一个重要的经验:谁拥有数据,谁对外提供操作这些数据(私有)的方法!
二.类和类的实例化
1.什么是类
类就是一类对象的统称。对象就是这一类具体化的一个实例。
举一个通俗的例子:我们在做饼干的时候会用到模具,模具就是一个类,而模具做出来的饼干就是对象。一个模具能做出多个饼干,那么一个类也能实例化多个对象。接下来用一段代码来展示具体用法:
class Person{
//成员变量/字段/属性
public String name;
public String sex;
public int age;
//成员方法/行为
public void show(String name,String sex,int age){
System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
}
}
2.类的实例化
定义:用类类型创建对象的过程,称为类的实例化
1. 类只是一个模型一样的东西,限定了类有哪些成员
2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
3. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东 西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
那么怎么实例化一个对象呢?我们通过new来实现
怎么调用类里面的方法呢?我们可以通过 对象引用.成员变量/成员方法 来调用类里面创建的变量及方法。
接下来上一段代码具体演示一下操作:
class Person{
//成员变量/字段/属性
public String name;
public String sex;
public int age;
//成员方法/行为
public void show(String name,String sex,int age){
System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
}
}
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();//实例化对象
person.show("Sarah","女",18);//调用show方法
}
}
就跟我们上面举的例子一样,通过一份设计图能建造多个房子,那么一个类也能实例化多个对象!
class Person{
//成员变量/字段/属性
public String name;
public String sex;
public int age;
//成员方法/行为
public void show(String name,String sex,int age){
System.out.println("姓名:"+name+" 性别:"+sex+" 年龄:"+age);
}
}
public class TestDemo {
public static void main(String[] args) {
//实例化多个对象
Person person1 = new Person();
Person person2 = new Person();
person1.show("Sarah","女",18);
}
}
三.类的成员
类的成员可以包含以下:字段、方法、代码块、内部类和接口等。这里我们重点讲解一下前三个
1.成员变量
定义在类中 、在方法外部的变量,我们称为 "字段" 或 "属性" 或 "成员变量"(三种称呼都可以, 一般不会严 格区分)
我们来看一段代码,试着输出一下成员变量的值
class Person{
//成员变量/字段/属性
public String name;
public String sex;
public int age;
}
public class TestDemo {
public static void main(String[] args) {
//实例化多个对象
Person person = new Person();
System.out.println(person.name);
System.out.println(person.sex);
System.out.println(person.age);
}
}
这里我们并没有初始化这三组成员变量,为什么还能输出null、null、0呢?我们在数据类型里面提到过,如果一个对象的成员变量没有显式设置初始值,将会输出默认值,下面是默认值规则,供大家参考:
注意:不能对null进行访问操作!因为null代表空引用,类似于C语言中的空指针,如果进行访问操作则会发生异常
2.方法
就像我们前面讲的洗衣机是一个对象,那么洗衣机洗衣服的功能就是洗衣机这个对象的方法这里,方法的定义就是 用于描述一个对象的行为!
class Person{
public String name ;
public int age;
public void show(String name,int age){
System.out.println("我叫"+name+",我今年"+age+"岁");
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.show("Sarah",18);
}
}
这里的show方法就是person这个对象自我展示的行为!需要注意的是,这样的 show 方法是和 person 实例相关联的. 如果创建了其他实例, 那么 show 的行为就会发生变化
class Person{
public String name ;
public int age;
public void show(String name,int age){
System.out.println("我叫"+name+",我今年"+age+"岁");
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.show("Wsy",18);
}
}
3.static关键字
静态成员变量
我们成员变量分为 普通成员变量和静态成员变量
普通成员变量也叫做实例的成员变量,静态成员变量也叫做类变量
首先我们来看看怎么访问静态成员变量
class Demo{
//成员变量/字段/属性
public static int num1;//创建一个静态成员变量
public int num2;//创建一个普通成员变量
}
public class TestDemo {
public static void main(String[] args) {
Demo demo = new Demo();
System.out.println(Demo.num1);
System.out.println(demo.num1);
}
}
我们发现通过方法名.静态成员变量虽然能得到结果,但是会有警告,所以我们最好通过类.静态成员变量来访问 静态成员变量
静态成员变量储存方式
我们知道对象是储存到栈上的,那么静态成员变量是储存到哪的呢?
class Demo{
//成员变量/字段/属性
public static int num1;//创建一个静态成员变量
public int num2;//创建一个普通成员变量
}
public class TestDemo {
public static void main(String[] args) {
Demo demo = new Demo();
Demo.num1++;
demo.num2++;
System.out.println(Demo.num1);
System.out.println(demo.num2);
System.out.println("-------------------");
Demo demo1 = new Demo();
Demo.num1++;
demo1.num2++;
System.out.println(Demo.num1);
System.out.println(demo1.num2);
}
}
来看看运行结果:
为什么在第二次++后num1和num2的值不一样呢?我们发现他们一个是静态成员变量,一个是成员变量,我们来具体分析一下他们储存的位置
通过分析,我们发现由static修饰的静态成员变量压根不依赖于对象!因为它并没有存放在堆上面,而是放在方法区里!无论你new多少个对象,num1就这么一个,所以num1的结果是2!
来看一个例子来看看静态成员变量的特点
class Demo{
//成员变量/字段/属性
public static int num1;//创建一个静态成员变量
public int num2;//创建一个普通成员变量
}
public class TestDemo {
public static void main(String[] args) {
Demo.num1++;
System.out.println(Demo.num1);
}
}
我们知道,如果访问普通成员变量不初始化一个对象是会报错的!但是静态成员变量却能正常运行!归根结底,还是我们前面说的,静态成员变量不依赖于对象!!
我们再来看一段代码看看是否会报错
class Demo{
//成员变量/字段/属性
public static int num1;//创建一个静态成员变量
public int num2;//创建一个普通成员变量
}
public class TestDemo {
public static void main(String[] args) {
Demo demo = null;
System.out.println(demo.num1);
}
}
我们前面提到了,null.任何东西都会出现空指针引用异常。那么这个时候为什么不报错呢?这里的 demo代表demo不指向任何对象,而我们已经说过静态成员变量的访问时不依赖于对象的,所以这里并没有发生异常。但如果通过 demo访问普通成员变量的话就会报错!
静态成员方法
成员方法也分为两种,一种是普通成员方法,一种是静态成员方法。
普通的成员方法又叫做实例的成员方法,静态的成员方法也叫做类方法。
我们先来看一下静态成员方法如何调用!请看代码
class Demo{
//成员变量/字段/属性
public String name;
public static void eat(String name){
System.out.println(name+"在吃饭");
}
public void sleep(String name){
System.out.println(name+"在睡觉");
}
}
public class TestDemo {
public static void main(String[] args) {
Demo.eat("Sarah");
}
}
静态成员方法能直接通过 类名.方法进行访问 而普通成员方法需要先实例化一个对象,然后通过 对象名.方法 进行访问
同理可推到出,在静态的成员方法内部也是不可以调用普通成员方法的,除非实例化一个对象
注意:我们曾经写的方法为了方便直接调用, 都统一加上了 static. 但实际上一个方法具体要不要带 static, 都需要是情形而定.
静态的在类加载的时候就已经定义好了,具体在后面的JVM中会讲解到。
总结-必看!!!
普通方法内部:不能定义静态方法变量static 能调用静态方法
静态方法内部:可以通过实例化对象来调用普通方法
4.toString方法
关于toString方法,我们来看一段代码
class Person{
public String name ;
public int age;
public void show(String name,int age){
System.out.println("我叫"+name+",我今年"+age+"岁");
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
}
这里先科普一下序列化和反序列化
序列化:把一个对象变成字符串
反序列化:把字符串变成对像
我们发现这里打印的是一个地址,按住ctrl,点击println,发现调用的是valueOf方法,同样的方法发现最后调用的是Object 的 toString 方法来打印
我们可以自己写一个toString方法,大家可以自己去实现。这里主要讲IDEA自己生成的toString方法。快捷键是alt+insert
使用toString方法的代码和运行结果如下
class Person{
public String name ;
public int age;
public void show(String name,int age){
System.out.println("我叫"+name+",我今年"+age+"岁");
}
@Override//重写
public String toString() {
return "Person{" +
"name='" + name + '\\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person);
}
}
ps:双引号里面的内容可以自己进行修改
5.匿名对象
没有引用的对象称为匿名对象
匿名对象只能在创建对象时使用
如果一个对象只是用一次, 后面不需要用了, 可以考虑使用匿名对象
用法展示:
public static void main(String[] args) {
new Person().name = "Sarah";
new Person().age = 18;
}
四.封装
面向对象编程的三大特征:继承 封装 多态
在我们写代码的时候经常会涉及两种角色: 类的实现者和类的调用者
封装的本质:让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就行了. 这样就降低了类使用者的学习和使用成本, 从而降低了复杂程度
1.private实现封装
private/ public 这两个关键字表示 " 访问权限控制 " .被 public 修饰的成员变量或者成员方法 , 可以直接被类的调用者使用被 private 修饰的成员变量或者成员方法 , 不能被类的调用者使用
具体private应该在哪种情况下使用呢 ,我们来看一段代码
class Person{
public String name = "张三";
public int age = 18;
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
System.out.println("我叫"+person.name+",我今年"+person.age+"岁");
}
}
这段运行起来没有任何问题。但是如果我们想把name改成myName,类的使用者就必须大规模得修改自己的代码。其次,类的使用者也必须清楚Person类内部的实现,这样学习成本太高。那么这个时候,我们可以使用封装
class Person{
private String name ;
private int age;
public void show(){
System.out.println("我叫"+name+",我今年"+age+"岁");
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.show("Sarah",18);
}
}
1.此时字段已经使用 private 来修饰, 类的调用者 (main 方法中 ) 不能直接使用, 而需要借助 show 方法。 此时类的使 用者就不必了解 Person 类的实现细节2.同时如果类的实现者修改了字段的名字, 类的调用者不需要做出任何修改 ( 类的调用者根本访问不到 name, age 这样的字段)
private 不光能修饰字段, 也能修饰方法通常情况下我们会把字段设为 private 属性, 但是方法是否需要设为 public, 就需要视具体情形而定 . 一般我们希望一个类只提供 " 必要的 " public 方法, 而不应该是把所有的方法都无脑设为 public
2.getter和setter方法
class Person{
private String name ;
private int age;
public void show(){
System.out.println("我叫"+name+",我今年"+age+"岁");
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.name = "Sarah";
person.show();
}
}
这段代码报错,我们来看看报错原因:
这个时候,如果需要获取/修改private这个属性,就需要使用gette和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;//this引用,调用该方法的对象
}
public void show(){
System.out.println("我叫"+name+",我今年"+age+"岁");
}
}
public class Test {
public static void main(String[] args) {
Person person = new Person();
person.setName("Sarah") ;
person.setAge(18);
person.show();
}
}
getName 即为 getter 方法, 表示获取这个成员的值setName 即为 setter 方法, 表示设置这个成员的值当 set 方法的形参名字和类中的成员属性的名字一样的时候,如果不使用 this, 相当于自赋值。 this 表示当前实例的引用
生成getter和setter方法的快捷键跟生成toString方法一样:alt+insert
五.构造方法
1.基本语法
构造方法是用来构造对象的。是一种特殊方法,使用new关键字实例化对象的时候会被自动调用,用于完成初始化操作
1. 方法名称必须与类名称相同2.构造方法没有返回值类型声明3. 每一个类中一定至少存在一个构造方法(没有明确定义,则系统自动生成一个无参构造)
1.如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数2.若类中定义了构造方法,则默认的无参构造将不再生成3.构造方法支持重载 . 规则和普通方法的重载一致
class Person{
private String name ;
private String sex ;
private int age;
//默认构造函数 构造对象
public Person(){
this.name = "A";
this.sex = "男";
this.age = 18;
}
//带有三个参数的构造方法
public Person(String name,String sex,int age){
this.name = name;
this.sex = sex;
this.age = age;
}
public void show(){
System.out.println("name: "+name+" sex: "+sex+" age: "+age);
}
}
public class Test {
public static void main(String[] args) {
Person person1 = new Person();
person1.show();
Person person2 = new Person("B","女",18);
person2.show();
}
}
2.this关键字
this代表当前对象的引用
this关键字共有三种使用方法
1.this.data:调用当前对象的属性
2.this.func():调用当前对象的方法
3.this():调用当前对象的其他构造方法 (只能存放在构造函数中)
接下来我们具体看看怎么使用,第一种用法其实我们在上面已经使用过,第二种用法也跟第一种用法大同小异,只不过一个调用的是属性,一个调用的是方法
public Person(String name,String sex,int age){
this.name = name;
this.sex = sex;
this.age = age;
}
接下来我们具体讲一下第三种使用
public Person(){
this("A","女",18);
}
需要注意的是,this()只能调用一个构造方法,且必须放在构造方法里的第一行使用
六.代码块
1.什么是代码块
代码块就是使用{}定义的一段代码
代码块分为四种:
本地代码块、静态代码块、实例代码块、同步代码块
2.本地代码块
public class Main {
public static void main(String[] args) {
{
int a = 10;
System.out.println(a);
}
}
}
用法比较少见,这里不再赘述
3.实例代码块
也叫构造代码块,一般用于初始化实例成员变量
class People{
private String name;
private int age;
{
this.name = "A";
this.age = 18;
}
public void show(){
System.out.println("name: "+name+" age: "+age);
}
}
public class Main {
public static void main(String[] args) {
People p = new People();
p.show();
}
}
4.静态代码块
使用 static 定义的代码块。 一般用于初始化静态成员属性。
class People{
private String name;
private int age;
private static int count = 0;//静态成员变量 由类共享数据 方法区
{
this.name = "A";
this.age = 18;
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);
}
}
public class Main {
public static void main(String[] args) {
People p = new People();
p.show();
}
}
所以我们知道执行顺序为:
静态代码块(只能执行一次、不能调用this方法、不被实例化都能执行)
实例代码块
构造方法
以上是关于Java-类和对象的主要内容,如果未能解决你的问题,请参考以下文章