一、定义一个类
类名命名:大驼峰
包括:字段、成员方法
class Person {
//字段 -> 属性 -> 成员变量
// --> 类的内部,方法的外部
// 成员变量:1. 普通成员变量,2. 静态成员变量
public String name = "gaobo";
public int age = 18;
// 一个对象存储到哪里,和被final修饰无关
public final int size1 = 10; // 对象中
public static final int size2 = 20; // 方法区
// 成员方法
// 1. 成员变量:普通成员方法,静态成员方法
public void eat() {
System.out.println(name+" 正在吃饭");
}
public void sleep() {
System.out.println(name+" 正在睡觉");
}
}
二、成员变量
1、怎样访问成员变量
普通成员变量的访问需要通过对象的引用
由 类 产生 对象 的过程:实例化,用new
由类Person实例化了一个对象
class Person {
public String name = "gaobo";
public int age = 18;
public void eat() {
System.out.println(name+" 正在吃饭");
}
public void sleep() {
System.out.println(name+" 正在睡觉");
}
}
public class TestDemo {
public static void main(String[] args) {
// 由类定义的变量:引用变量
Person person1 = null;
Person person2 = new Person();
}
}
2、局部变量,成员变量
- 局部变量没有赋初值,打印报错
- 成员变量如果没有赋值,打印的name是null,而age是0
成员变量没有赋初值的默认值:
* 整数 byte short int long(默认值:0)
* 浮点数 float double(默认值:0.0)
* 基本数据类型 字符 char(默认值:'\u0000')
* 布尔 boolean(默认值:false)
* 数据类型
* 引用类型 String 数组 类 接口 枚举……(默认值:null)
*
以下打印null:
class Person {
public String name;
public int age;
public void eat() {
System.out.println(name+" 正在吃饭");
}
public void sleep() {
System.out.println(name+" 正在睡觉");
}
}
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
}
}
3、每个对象都有 name age
class Person {
public String name;
public int age;
public void eat() {
System.out.println(name+" 正在吃饭");
}
public void sleep() {
System.out.println(name+" 正在睡觉");
}
}
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();
person.name = "bit";
person.age = 10;
System.out.println(person.name); // bit
System.out.println(person.age); // 10
System.out.println("=======================");
Person person2 = new Person();
System.out.println(person2.name); // null
System.out.println(person2.age); // 0
}
}
三、成员方法
1、成员方法的访问
class Person {
public String name;
public int age;
public void eat() {
System.out.println(name+" 正在吃饭");
}
public void sleep() {
System.out.println(name+" 正在睡觉");
}
}
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();
person.eat(); // gaobo 正在吃饭
person.sleep(); // gaobo 正在睡觉
}
}
四、静态成员
字段-属性-成员变量:
1.普通成员变量
2.静态成员变量 --> 类名.静态的成员属性/方法
class Person {
// 普通的成员变量 -都是属于对象的
public String name; // 实例变量 存放在对象内
public int age;
// 静态成员变量 -类变量 -> 方法区
public static int count;
public void eat() {
System.out.println(name+"正在吃饭!");
}
public void sleep() {
System.out.println(name+"正在睡觉!");
}
}
1、方法区
class Person {
public String name;
public int age;
// 静态成员变量 -类变量 -> 方法区
public static int count;
}
public class TestDemo {
public static void main3(String[] args) {
Person person1 = new Person();
person1.count++;
System.out.println(Person.count); // 1
System.out.println("===================");
Person person2 = new Person();
person2.count++;
System.out.println(Person.count); // 2
}
public static void main2(String[] args) {
Person person1 = new Person();
person1.age++;
System.out.println(person1.age); // 1
System.out.println("===================");
Person person2 = new Person();
person2.age++;
System.out.println(person2.age); // 1
}
public static void main1(String[] args) {
Person person = new Person();
person.count = 1999;
System.out.println(person.count); // 1999
}
}
2、访问静态成员变量
class Person {
public String name;
public int age;
// 静态成员变量 -类变量 -> 方法区
public static int count;
}
public class TestDemo {
public static void main(String[] args) {
/*Person person1 = new Person();
person1.count++;*/
// 通过类名访问静态成员变量
// 类名.静态的成员属性/方法
// 不需要new两个对象 节省了2个对象的空间
Person.count++;
System.out.println(Person.count); // 1
System.out.println("===================");
/*Person person2 = new Person();
person2.count++;*/
Person.count++;
System.out.println(Person.count); // 2
// 方法区
}
}
2、访问静态方法:直接用类名
class Person {
public void eat() {
System.out.println(name+" 正在吃饭");
}
// 类方法/静态方法
public static void staticFunc() {
System.out.println("static::func()");
}
}
public class TestDemo {
public static void main(String[] args) {
// 访问静态方法:直接用类名
Person.staticFunc();
// 需要引用指向对象
Person p = new Person();
p.eat();
}
}
3、注意事宜
① 普通的方法内部,不能定义静态的变量
- static 定义的变量,是类变量,属于类
- eat方法的调用,需要对应的引用来调用,但是如果可以定义static的变量,类名Person就可以调用
class Person1 {
public String name;
public int age;
public static int count;
public void eat() {
// static int size = 0; // err
System.out.println(name+"正在吃饭!");
}
}
public class TestPerson {
public static void main(String[] args) {
}
}
② 静态的成员变量,是不可以在方法中定义的
class Person1 {
public String name;
public int age;
public static int count;
// 类方法/静态方法
public static void staticFunc1() {
// static int size = 0; // err
count = 1; // 可以赋值静态成员变量
}
}
public class TestPerson {
public static void main(String[] args) {
}
}
③ 普通方法内部,可以调用静态的方法
class Person {
public String name;
public int age;
public static int count;
public void sleep() {
// 普通方法依赖于对象,静态方法不依赖对象
staticFunc();
System.out.println(name+"正在睡觉!");
}
// 类方法/静态方法
public static void staticFunc() {
System.out.println("static::func()");
}
}
public class TestPerson {
public static void main(String[] args) {
Person person = new Person();
p.sleep();
}
}
④ 静态方法内部,不能调用普通方法
class Person1 {
public String name;
public int age;
public static int count;
public void sleep() {
System.out.println(name+"正在睡觉!");
}
// 类方法/静态方法
public static void staticFunc() {
// 通过类名就可以调用静态方法,而普通方法需要对象
// sleep(); // err
System.out.println("static::func()");
}
}
public class TestPerson {
public static void main(String[] args) {
}
}
例1:
public class TestPerson {
public static void func1() {
}
public void func2() {
}
public class TestDemo {
public static void main(String[] args) {
func1(); // ok
// func2(); // err 普通成员方法需要对象
TestDemo testDemo = new TestDemo();
testDemo.func2(); // ok
}
}
main函数为什么是静态的
main是不是静态的都可以,取决于JVM如何实现的
例2:
class Test{
public int a;
public static int count;
}
public class Main{
public static void main(String[] args) {
Test t1 = new Test();
t1.a++; // 1
Test.count++; // 1
System.out.println(t1.a); // 1
System.out.println(Test.count); // 1
System.out.println("============");
Test t2 = new Test();
t2.a++; // 1
Test.count++; // 2
System.out.println(t2.a); // 1
System.out.println(Test.count); // 2
}
}
五、引用
1、null
public class TestDemo {
public static void main(String[] args) {
Person person = null; // 此引用不指向任何对象
}
}
2、该引用指向?
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();
Person person1 = person; // person1这个引用指向person这个引用所指向的对象
}
}
3、一个引用能否同时指向多个对象?
public class TestDemo {
public static void main(String[] args) {
// 一个引用不能同时指向多个对象
Person person = new Person();
person = new Person();
person = new Person();
person = new Person();
person = new Person(); // 最后一次
}
}
4、引用一定在栈上吗?
不一定
public class TestDemo {
// 成员变量
Person person = new Person();
public static void main(String[] args) {
TestDemo testDemo = new TestDemo();
Person person = new Person();
}
}
🍳
六、toString
方法会在 println 的时候被自动调用
序列化:对象转成字符串
class Person {
/* public String toString() {
return "姓名:"+name+" 年龄"+age;
}*/
// 右击generate toString
// 重写Object的toString方法
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person); // Person@1b6d3586
// 打印此引用的值 toString
}
}
自动生成:
右击generate toString
重写Object的toString方法
七、封装
1、什么是封装
在我们写代码的时候经常会涉及两种角色: 类的实现者和类的调用者.
封装的本质就是让类的调用者不必太多的了解类的实现者是如何实现类的, 只要知道如何使用类就行了.
这样就降低了类使用者的学习和使用成本, 从而降低了复杂程度
被 public 修饰的成员变量或者成员方法, 可以直接被类的调用者使用.
被 private 修饰的成员变量或者成员方法, 不能被类的调用者使用
封装:只能在当前类使用 -安全
2、getter和setter方法
如果name被private修饰,就只能在当前类中使用
需要获取或者修改这个 private 属性,就需要使用getter和setter方法
class Person {
private String name;
/*
public String getName() {
return name;
}
public void setN(String myN) {
name = myName;
}*/
// 右击generate Getter Setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name; //this引用 代表**当前对象的引用**
}
}
public class TestDemo {
public static void main(String[] args) {
Person person = new Person();
// 赋值
person.setN("bit");
// 获取
System.out.println(person.getN()); // bit
}
}
3、注意问题
- getName 即为 getter 方法, 表示获取这个成员的值
- setName 即为 setter 方法, 表示设置这个成员的值
- 当set方法的形参名字和类中的成员属性的名字一样的时候,如果不使用this, 相当于自赋值. this 表示当前实例的引用
八、构造方法
构造方法是一种特殊方法, 使用关键字new实例化新对象时会被自动调用, 用于完成初始化操作
方法名称与类名称相同,且构造方法比较特殊,没有返回值
构造方法是干什么的 -> 一个对象的产生/实例化new 需要:
1.为对象分配内存空间
2.调用合适的构造方法 --(构造方法不止一个)
class Person {
// 构造方法
public Person() {
System.out.println("Person()::不带参数的构造方法");
}
public Person(String name) {
this.name = name;
System.out.println("Person(String)::带一个String 类型参数的构造方法");
}
// 重载
public Person(String name, int age) {
this.name = name;
this.age = age;
System.out.println("Person(String)::带2个String 类型参数的构造方法");
}
}
public class TestDemo {
public static void main13(String[] args) {
Person person = new Person(); // Person()::不带参数的构造方法
System.out.println("=====================");
/*
1. 如果类中没有提供任何的构造函数,那么编译器会默认生成一个不带有参数的构造函数
一个类,至少会有一个改造方法
2. 若类中定义了其他构造方法,则编译器默认生成的无参构造将不再生成
3. 构造方法支持重载(方法名称相同,参数列表不同,返回值不做要求). 规则和普通方法的重载一致
*/
// 在实例化对象时,调用了构造方法
// 同时会给name传值
Person person1 = new Person("bit"); // Person(String)::带一个String 类型参数的构造方法
System.out.println("======================");
Person person2 = new Person("bit", 19); // Person(String)::带2个String 类型参数的构造方法
}
}
九、this关键字
注意:this代表当前对象——err
调用完构造方法才会实例化生成对象,this只代表为对象分配内存空间,第二步还未完成,
- this.data --> 调用当前对象的属性
- this.func() --> 调用当前对象的方法 (静态方法里不能用this)
- this() --> 调用当前对象的其他构造方法
只能存放在构造方法中
class Person {
public String name;
public int age;
public Person() {
// this调用构造函数
// 必须放在第一行
this("zhangsan"); // ->调用带有一个参数的构造方法
System.out.println("Person()::不带参数的构造方法");
}
public Person(String name) {
this.name = name; // 给name赋值
System.out.println("Person(String)::带一个String 类型参数的构造方法");
}
}
public class Print {
public static void main(String[] args) {
Person person = new Person(); // ->调用不带参数的构造方法
// Person(String)::带一个String 类型参数的构造方法
// Person()::不带参数的构造方法
System.out.println(person);
// Person{name='zhangsan', age=0}
}
}
十、代码块
1、四种代码块
本地代码块,实例代码块,静态代码块,同步代码块
class Person {
{
this.age = 50; // 实例代码块可以实例数据成员 静态代码块不能
System.out.println("实例代码块");
}
static {
System.out.println("静态代码块");
}
}
public class TestDemo {
public static void main(String[] args) {
{
// 本地代码块
}
}
}
2、代码块是如何被调用的
运行此代码
class Person {
{
System.out.println("实例代码块");
}
static {
System.out.println("静态代码块");
}
}
public class TestDemo {
public static void main(String[] args) {
Person person1 = new Person();
/**打印:
* 静态代码块
* 实例代码块
* Person()::不带参数的构造方法
*/
System.out.println("====================");
Person person2 = new Person();
/**
* 第二次实例化对象:
* 静态代码块
* 实例代码块
* Person()::不带参数的构造方法
* ====================
* 实例代码块
* Person()::不带参数的构造方法
*/
}
}
静态代码块不管生成多少个对象,其只会执行一次,且是最先执行的。
静态代码块不用实例化 就可以被执行 (类加载的时候)
3、静态变量test打印多少?
test打印10还是99
class Person {
public static int test = 10;
{
System.out.println("实例代码块");
}
static {
test = 99;
System.out.println("静态代码块");
}
}
public class TestDemo {
public static void main(String[] args) {
System.out.println(Person.test);
// 99
// 如果都是静态的,和定义的顺序有关
// 字段在前 99
// 静态代码块在前 10
// 如果test没有初始化默认值0:
// 字段在前 99
// 静态代码块在前 99
}
}
十一、匿名对象
没有引用的对象称为匿名对象.
匿名对象只能在创建对象时使用.
如果一个对象只是用一次, 后面不需要用了, 可以考虑使用匿名对象
class Person {
public String name;
public void eat() {
System.out.println(name+" 正在吃饭");
}
public void sleep() {
System.out.println(name+" 正在睡觉");
}
}
public class TestDemo {
public static void main(String[] args) {
// 一次性
new Person().eat(); // new对象 调用eat
new Person().sleep();
System.out.println(new Person());
System.out.println("==============");
// 只用一次对象
Person person1 = new Person();
person1.eat();
person1.sleep();
System.out.println(person1);
}
}
十二、用类编写代码:
1、编写一个类Calculator
编写一个类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 TestDemo {
public static void main(String[] args) {
Calculator calculator = new Calculator();
calculator.setNum1(1);
calculator.setNum2(2);
System.out.println(calculator.add());
}
}
2、实现交换两个变量的值。要求:需要交换实参的值
class MyValue {
public int val;
}
public class TestDemo {
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.val+" "+ myValue2.val); // 20 10
}
}