类和对象
Java是一门面向对象的编程语言,它关注的是对象,将一个事情拆分成不同的对象,靠对象之间的交互完成的。所以它注重的是利用各种对象通过逻辑串联起来解决问题。
类的实例化
类是一类对象的统称,就像做东西的一个模板,不管最后东西的材质颜色是怎样的,大体的形状也会和类相差不多,而那些对象就是做成的各种东西。所以一个类可以产生无数的对象,这样的过程就叫做实例化。
实例化是如何实现的呢?那肯定得先创建一个类啊:
class<class_name>{
field;//成员属性
method;//成员方法
}
创建好了之后就该实例化了:
<class_name> <对象名>=new <class_name>();
class为定义类的关键字,ClassName为类的名字,{}中为类的主体。
类中的元素称为:成员属性。类中的函数称为:成员方法。
比如这样的代码:
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 javaClass {
public static void main(String[] args) {
Person person=new Person();//通过new来实例化对象
person.eat();//实例方法的调用需要通过对象的引用调用
person.sleep();
}
}
前面class就是在创建类,后面主函数里面就在实例化对象,还通过对象的调用实现了对象中方法的调用,而这里的new关键字就是用于创建一个对象的实例。
类的成员
类的成员主要包括有字段、方法、代码块、内部类和接口等
字段/属性/成员变量
class Person{
public String name;
public int age;
}
public class javaClass {
public static void main(String[] args) {
Person person=new Person();
System.out.println(person.name);
System.out.println(person.age);
}
}
运行结果是null和0,可以看出对于引用类型,初始值默认一般为null,而对于基本数据类型,初始值默认为0
值得注意的是null在Java中为“空引用”,表示不引用任何的对象,如果对null进行.操作就会引发异常。比如上面的代码加上这段代码:
System.out.println(person.name.length());
person.name是一个空指针,不指向任何的对象,它想要.length获取字符串的长度是肯定不行的,系统就会报错。
方法
方法就是在类里面定义一个方法,比如在class里面加入:
public void show(){
System.out.println("my name is "+name+",and age is "+age);
}
后面在main函数里面通过调用person.show就能使用show函数了,其实就相当于是在class类里面创建一个函数接下来可以来使用
static关键字
Java中的静态属性和类相关, 和具体的实例无关。换句话说, 同一个类的不同实例共用同一个静态属性
修饰成员变量
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);
}
}
比如这样一串代码,其中a是普通成员变量,count是静态成员变量,a在第二次new一个对象时又回到了默认初始值,而count却没有变,因为它是静态的,在这个类里面只要发生改动就不会再被new刷新。所以代码结果是1 1 1 2
在内存中是这样的:class类中的对象都在栈中,分别指向不同的堆,普通成员变量就存储在堆中,而静态成员变量就存储在方法区中
修饰方法
在方法上应用static关键字就叫静态方法,静态方法有这些特点:
静态方法属于类,而不属于类的对象。
可以直接调用静态方法,而无需创建类的实例。
静态方法可以访问静态数据成员,并可以更改静态数据成员的值。
class Person{
public int age=20;
public static int count=20;
public static void swap(){
count=100;
//在这里如果是age=100就会编译出错,因为age不是静态数据成员
}
Person.swap();
System.out.println(Person.count);
这只是一部分,最后调用静态方法swap将静态数据count值改为了100,而静态方法却不能对非静态的成员变量值进行修改
静态方法和实例无关, 而是和类相关,所以静态方法不能直接使用非静态数据成员或调用非静态方法(非静态数据成员和方法都是和实例相关的)
static不是想加就加的,但是main函数一定要加上static
封装
既然Java是面向对象的编程语言,那么必然涉及到类的实现者和类的调用者。封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就行了。这样就降低了类使用者的学习和使用成本, 从而降低了复杂程度。
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给封装起来了,换到Test这个类里面时是不能访问到的,因此只能通过show方法,而使用者就不必知道Person类里面的细节,只要能用出来就行
private 不光能修饰字段, 也能修饰方法
通常情况下我们会把字段设为 private 属性, 但是方法是否需要设为 public, 就需要视具体情形而定. 一般我们希望一个类只提供 “必要的” public 方法, 而不应该是把所有的方法都无脑设为 public
getter和setter方法
class Person{
public String name="shi lin";
public int age=20;
public static int count=20;
public void show(){
System.out.println("my name is "+name+",and age is "+age);
}
public static void swap(){
count=100;
//在这里如果是age=100就会编译出错,因为age不是静态数据成员
}
private String baobei;
private int year;
public String getBaobei() {
return baobei;
}
public void setBaobei(String baobei) {
this.baobei = baobei;
}
}
public class javaClass {
public static void main(String[] args) {
Person person=new Person();
System.out.println(person.name);
System.out.println(person.age);
person.show();
Person.swap();
System.out.println(Person.count);
person.setBaobei("shi lin");
System.out.println(person.getBaobei());
}
}
其中getbaobei和setbaobei就是getter和setter方法,表示获取和设置这个成员的值,而这个成员一般都是private封装起来了的
在 IDEA 中可以使用 alt + insert (或者 alt + F12) 快速生成 setter / getter 方法;在 VSCode 中可以使用鼠标右键->菜单 -> 源代码操作 中自动生成 setter / getter 方法
构造方法
构造方法使用关键字new会被自动调用,用于完成初始化的操作
1.它的方法名和类名是相同的
2.没有返回值
实例化一个对象要分为两步:
1.为对象分配内存
2.调用合适的构造方法(构造方法不止一个)
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();
}
}
比如这样几个构造函数,它就跟函数的重载类似,有相同的方法名称,但是有不同的变量,在调用时就要在变量中体现出不同的构造函数来实现不同的功能
this关键字
this代表的是当前对象的引用
静态的方法里不能使用this,因为静态的方法不依赖于对象
//默认构造函数 构造对象
public Person() {
//this调用构造函数
this("gaobo", 12, "man");//必须放在第一行进行显示
}
//这两个构造函数之间的关系为重载。
public Person(String name,int age,String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
this不仅可以指向变量,也可以指向构造方法,同时注意一定要写在第一行,这行代码就是先走第一个构造函数,然后this指向第二个构造函数,跑完后再回来,就将gaobo,12,man附到构造变量中了
代码块
代码块就是用{}定义的一段代码
普通代码块
用的很少,它是定义在方法中的代码块
构造代码块
定义在类中的代码块,也叫实例代码块,一般用于初始化成员变量
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()!");
}
来看这样一个代码,上面的Person里面就是普通代码块,它虽然在实例代码块的上面,但是最终结果是先输出I am instance init()!,同时也可以看到在实例代码块中没有加任何的修饰符,直接就一个大括号括起来了
静态代码块
使用static定义的代码块,一般用于初始化静态的成员变量
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()!");
}
比如看这样一行代码,首先静态代码有这样的两个特性:
1.静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的
2.静态代码块执行完毕后, 实例代码块(构造块)执行,再然后是构造函数执行
所以这个代码首先是要输出I am static init()!,然后I am instance init()!,最后才是输出后续的内容
toString的重写
在输出过程中我们会经常用到println,每次都一个一个的打出来是不方便的,而println里面引用了toString方法,所以我们可以通过重写toString的方法来达到方便的使用
IDEA快速生成Object的toString方法快捷键:alt+f12(insert)
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}