IDEA快捷键/模板快捷键
COMMAND |
TODO |
alert+insert |
自动生成构造方法 |
ctrl+h |
查看类的层级关系 |
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| class 类名称 { 属性 (变量) ; 行为 (方法) ; }
class Person { String name ; int age ; public void get() { System.out.println("姓名:" + name + ",年龄:" + age); } } 对象.属性:表示调用类之中的属性; 对象.方法():表示调用类之中的方法。
|
构造器/构造方法
1 2 3 4 5 6 7
| new一个对象时,就会调用构造器,完成对象属性的初始化 结构如下: [修饰符,比如public] 类名 (参数列表,可以没有参数){ } 1.方法名和类名必须一致 2.构造器无返回值
|
默认构造器
1 2 3 4 5 6
| 如果没有定义构造器,则会默认一个无参构造器,这就是为什么你定义了一个对象,比如 People,没有定义任何构造器却可以new这个对象,比如 new People() 。如果自定义了构造器,则会覆盖默认构造器。 public class People { public People() {
} }
|
禁止对象被外部创建
1 2 3 4 5 6
| 不希望定义的对象被外部创建(典型的就是单例了),那直接将构造器的修饰符改为 private 即可。这样就不能在外部通过new来创建这个对象了。 public class People { private People(){
} }
|
构造器重载
1 2 3 4 5 6 7 8 9 10
| public class People { public People(){
} public People(String str){
} }
|
this
1
| this 是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。
|
直接引用
形参与成员名字重名,用this来做区分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| class Person { private int age = 10; public Person(){ System.out.println("初始化年龄:"+age); } public int GetAge(int age){ this.age = age; return this.age; } } public class test1 { public static void main(String[] args) { Person Harry = new Person(); System.out.println("Harry's age is "+Harry.GetAge(12)); } } 初始化年龄:10 Harry's age is 12
|
类加载
创建实例对象时(new)
创建子类实例时,父类也会被加载
使用类的静态成员(静态方法、静态属性)
包
1 2 3 4
| 本质:通过创建不同的文件夹/目录来保存类文件 package com.todo package--->关键字 com.todo--->包名
|
作用
访问修饰符
Example |
TODO |
public |
对外公开 |
proctected |
对子类和同一个包中的类公开 |
默认 |
向同一个包中的类公开 |
private |
只有类本身可以访问,不对外公开 |

继承
1 2 3 4
| 格式: class 子类 extends 父类{
}
|
Example:
1 2 3 4 5 6 7 8 9 10
| 公共类student public class student{ public String name; int age; double score;
public void showInfo(){ System.out.println("学生:"+name+" 年龄:"+age+"scroe:"+score); } }
|
1 2 3 4 5 6 7
| 子类:小学生 public class pupil extends student{ public void testing(){ System.out.println("小学生"+name+"正在考试....."); } }
|
1 2 3 4 5 6 7
| 子类:大学生 public class graduate extends student{ public void testing(){ System.out.println("小学生"+name+"正在考试....."); } }
|
1 2 3 4 5 6 7 8 9 10
| 使用类 public class use{ public static void main(String[] args) { pupil p = new pupil(); p.name="李华"; p.testing(); p.setScore(60); p.showinfo(); } }
|
继承细则
1 2
| 子类继承了所有的属性和方法,但是私有属性和方法不能在子类中直接访问, 要通过父类提供公共的方法去访问
|
1 2 3 4 5 6 7 8
| 子类必须调用父类的构造器,完成父类的初始化 实际是编译器会在子类的构造器中添加super()来 调用父类的无参构造器 Example: public class sub extends base{ super(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会调用父类的无参构造器,如果父类没有 无参构造器,则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作 Example: 父类无无参构造器,有有参构造器: ps:当父类有了有参构造器后无参构造器就被覆盖了,就没有无参构造器了 public class base(){ public String name; public int age; public double score;
public base(String name,int age){ } } 这时必须要在子类的构造器中使用super去指定使用父类的构造器,来完成对父类的初始化 public class sub extends base(){ public sub(){ super("李华",22) } }
|
1
| 如果希望调用子类的指定构造器,显示的在子类中调用super()申明调用的是哪一个
|
1
| super()和this()都只能放在构造器中的第一行,因此不能在构造器中共存;
|
1 2
| java所有类都是Object类的子类 父类构造器的调用不限于直接父类,将一直往上追溯到Object类(低级父类)
|

1 2
| java是单继承机制,子类最多只能继承一个父类 若想让A同时继承B,C类,可以让A继承B,B继承C来实现
|
super()
super()代表父类的引用,用于访问父类的属性,方法,构造器
- 访问父类的属性,但不能访问父类的私有属性。super.属性名
- 访问父类的方法,但不能访问父类的私有方法。super().方法名()
- 访问父类的构造器
super()细则
- 调用父类构造器的好处,父类的属性由父类初始化,子类的属性由子类初始化
- 当子类中有和父类重名的属性、方法时,为了访问父类的必须通过super。如果没有重名则super、this、直接返回的效果一致
- super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员
- 如果多个基类(上级类)中都有同名的成员,使用super访问时遵循就近原则
方法重写override
1
| 如果子类有方法和父类的方法:名称、返回类型、参数都一致,就说子类的方法重写了父类的方法
|
多态
它允许同一个方法或接口在不同对象上具有不同的实现方式,Java作为一种面向对象的编程语言,广泛地利用了多态特性来提高代码的灵活性和可扩展性。
方法的多态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com;
public class use { public static void main(String[] args) { A a =new A(); System.out.println(a.sum(10,20)); System.out.println(a.sum(10,20,30));
B b = new B(); a.say(); b.say(); } } class B{ public void say(){ System.out.println("B say()方法被调用"); } }
class A extends B{ public int sum(int a,int b){ return a+b; } public int sum(int a,int b,int c){ return a+b+c; } public void say(){ System.out.println("A say()方法被调用"); } }
|
重载: 这里传入不同的参数就调用不同的sum()方法,体现了多态
重写: 父类和子类中都有say()方法,但是对象不同,因此会根据对象去调用不同的方法,体现多态
对象的多态
一个对象的编译类型和运行类型可以不一致
编译类型在定义对象时,就确定了,不能改变
运行类型是可以变化的
编译类型看定义时 ‘=’ 的左边,运行类型看 ‘=’ 号的右边
1 2 3 4 5 6 7
| package com;
public class Animal { public void cry(){ System.out.println("Animal() 动物在叫唤"); } }
|
1 2 3 4 5 6 7 8
| package com;
public class Dog extends Animal{ public void cry(){ System.out.println("Dog() 小狗汪汪叫"); } }
|
1 2 3 4 5 6 7 8
| package com;
public class Cat extends Animal{ public void cry(){ System.out.println("Cat() 小猫喵喵叫"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com;
public class use { public static void main(String[] args) { Animal animal = new Dog(); animal.cry();
Animal animal = new Cat(); animal.cry(); } }
|
Summary:一个父类的对象引用可以指向它的子类的对象,在运行时是以运行类型为主的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com;
public class Master { private String name; public Master(String name){ this.name=name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public void feed(Animal animal,Food food){ System.out.println("主人: "+this.name+"给"+animal.getName()+"喂"+food.getName()); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com;
public class Animal { private String name;
public Animal(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
|
1 2 3 4 5 6 7 8
| package com;
public class Dog extends Animal{
public Dog(String name) { super(name); } }
|
1 2 3 4 5 6 7 8
| package com;
public class Cat extends Animal{
public Cat(String name) { super(name); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com;
public class Food { private String name; public Food(String name){ this.name=name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; } }
|
1 2 3 4 5 6 7
| package com;
public class Bone extends Food{ public Bone(String name){ super(name); } }
|
1 2 3 4 5 6 7 8 9
| package com;
public class Fish extends Food{
public Fish(String name) { super(name); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com;
public class use { public static void main(String[] args) { Master master = new Master("李华");
Animal animal = new Dog("旺财"); Food food =new Bone("大棒骨");
Animal animal1 = new Cat("咪咪"); Food food1 = new Fish("小黄鱼");
master.feed(animal,food); master.feed(animal1,food1); } }
|
向上转型
本质: 父类的引用指向了子类的对象
特点:
1:可以调用父类中的所有成员(须遵守访问权限)
2:不能调用子类中特有成员和方法
3:最终运行效果看子类的具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com;
public class Animal { String name="动物"; int age=10;
public void run(){ System.out.println("跑"); }
public void sleep(){ System.out.println("睡"); }
public void eat(){ System.out.println("吃"); }
public void show(){ System.out.println("你好"); } }
|
1 2 3 4 5 6 7 8 9 10
| package com;
public class Cat extends Animal{ public void eat(){ System.out.println("猫吃鱼"); } public void CatchMouse(){ System.out.println("猫抓老鼠"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com;
public class use { public static void main(String[] args) { Animal animal = new Cat(); Object obj = new Cat();
animal.eat(); animal.run(); animal.show(); animal.sleep(); } }
|
向下转型
语法: 子类类型 引用名 = (子类类型) 父类引用;
Detail:
- 只能强转父类的引用,不能强转父类的对象
- 要求父类的引用必须指向的是当前目标类型的对象
- 当向下转型时可以使用子类类型中的所有成员
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| package com;
public class Animal { String name="动物"; int age=10;
public void run(){ System.out.println("跑"); }
public void sleep(){ System.out.println("睡"); }
public void eat(){ System.out.println("吃"); }
public void show(){ System.out.println("你好"); } }
|
1 2 3 4 5 6 7 8 9 10
| package com;
public class Cat extends Animal{ public void eat(){ System.out.println("猫吃鱼"); } public void CatchMouse(){ System.out.println("猫抓老鼠"); } }
|
1 2 3 4 5 6 7
| package com;
public class Dog extends Animal{ public void WatchDoor(){ System.out.println("小狗看门"); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package com;
public class use1 { public static void main(String[] args) { Animal animal = new Cat();
Cat cat = (Cat) animal;
cat.CatchMouse(); } }
|
属性重写问题
Simple:instanceof 用于判断某个变量的运行类型为xx类型或xx类型的子类型
1 2 3 4 5 6 7
| package com;
public class Base { int a=20;
}
|
1 2 3 4 5 6
| package com;
public class Sub extends Base{ int a=10; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com;
public class use { public static void main(String[] args) { Sub sub = new Sub();
System.out.println(sub instanceof Sub); System.out.println(sub instanceof Base);
Base base =new Sub(); System.out.println(base instanceof Base); System.out.println(base instanceof Sub); } }
|
动态绑定机制
当调用对象方法 的时候,该方法会和该对象的内存地址/运行类型 绑定
当调用对象属性 时,没有动态绑定机制 ,哪里声明,哪里使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com;
public class Base { public int i = 10; public int sum(){ return geti()+10; } public int sum1(){ return i+10; } public int geti(){ return i; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com;
public class Sub extends Base{ public int i=20;
public int geti(){ return i; } public int sum1(){ return i+10; }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com;
public class use { public static void main(String[] args) { Base base = new Sub();
System.out.println(base.sum()); } }
|
==操作符
- 既可以判断基本数据类型,也可以判断引用数据类型
- 判断基本数据类型时判断值是否相等
- 判断引用数据类型时则判断地址是否相等,即判断是否是同一个对象
equals()方法
- equals()方法是Object类中的一个方法,只能判断引用类型
- 默认判断的是地址是否相同,但是子类中往往会重写此方法,用于判断内容是否相同
1 2 3
| public boolean equals(Object obj) { return (this == obj); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
|
1 2 3 4 5 6
| public boolean equals(Object obj) { if (obj instanceof Integer) { return value == ((Integer)obj).intValue(); } return false; }
|
hashcode
总结:
- Object类中的一个方法
- 提高具有哈希结构的容器的效率
- 两个引用,如果指向同一个对象,则哈希值一定是一样的
- 两个引用,如果指向的是不同对象,则哈希值是不一样的
- 哈希值主要根据内部地址转换得来,不能完全将哈希值等价于地址
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com;
public class test { public static void main(String[] args) { AA aa = new AA(); AA aa1 = aa; AA aa2 = new AA(); System.out.println(aa.hashCode()); System.out.println(aa1.hashCode()); System.out.println(aa2.hashCode());
} } class AA{}
|
toString
SourceCode:返回全类名(包名+类名)+”@”+hashcode的16进制
1 2 3
| public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
|
- Object类中的一个方法
- 当输出一个对象时默认调用toString方法
类变量/静态变量
类变量也叫静态变量,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的值都是相同的,任何一个该类的对象去修改它时,修改的也是同一个变量。
语法:
访问修饰符 static 数据类型 变量名;
public static int count = 0;
访问类变量:
类名.静态变量(推荐)
对象名.静态变量
注意:类变量随着类的加载而创建,所以即使没有创建对象实例也可以访问
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com;
public class test { public static void main(String[] args) { System.out.println(AA.name); AA aa = new AA(); System.out.println(aa.name);
} } class AA{ public static String name = "你好"; }
|
类方法/静态方法
静态方法是属于类而不是类的实例的方法。它可以在不创建类的实例的情况下被调用。
静态方法通常用于执行与类相关的操作,而不需要访问或修改特定实例的状态。
1 2 3 4 5 6 7 8 9
|
public static int getNum(){ return num; }
类名.方法名 对象名.方法名
|
内部引用:在静态方法中不能使用this关键字,因为它没有当前对象的引用。实例方法可以使用this来引用当前对象
生命周期:静态方法在类加载时初始化,实例方法在对象创建时初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| package com;
public class Student { public String name; public static double fee=0;
public Student(String name){ this.name=name; }
public static void payFee(Double fee){ Student.fee += fee; }
public static void showFee(){ System.out.println(Student.fee); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com;
public class use { public static void main(String[] args){
Student lihua = new Student("李华"); Student.payFee(145.3);
Student zhangsan = new Student("张三"); Student.payFee(142.3);
System.out.println(Student.fee);
} }
|
代码块
代码化块又称为初始化块,属于类中的成员,类似于方法,将逻辑语句封装在方法体中,通过{ }包围起来。但其和方法不同,没有方法名、返回值、参数,只有方法体,且不用通过对象或类显式调用,而是在加载类时或创建对象时被隐式调用。
修饰符可写可不写,写的话只能写static
有static的叫静态代码块,没static的叫普通代码块
逻辑语句可以为任何逻辑语句。(输入、输出、循环、方法调用、判断等)
最后的 ‘;’ 可写可不写
有static修饰(静态代码块):作用是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。
无static修饰(普通代码块):每创建一个对象都会执行一次
普通的代码块,在创建对象实例时,会被隐式的调用,被创建一次就会调用一次。
如果只是使用类的静态成员(静态方法、静态属性)时,普通代码并不会执行
普通的代码块,在创建对象实例时,会被隐式的调用,被创建一次就会调用一次。
如果只是使用类的静态成员(静态方法、静态属性)时,普通代码并不会执行
静态代码块只能调用静态方法、静态属性
普通代码块可以调用任意成员
调用顺序
1:先是静态属性、静态代码块的调用。它们两个的优先级一样,如果它们同时存在,则按照顺序进行初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com;
public class block { public static void main(String[] args) { A a = new A(); } } class A{ public static int num=getNum(); static{ System.out.println("静态代码块被调用"); } public static int getNum(){ System.out.println("静态属性被调用"); return 10; } }
|
2:在调用普通代码块和普通属性的初始化,它们两个的优先级一样,如果同时存在,则按顺序
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| package com;
public class block { public static void main(String[] args) { A a = new A(); } } class A{ public static int num=getNum(); public String name = getName(); static{ System.out.println("静态代码块被调用"); } { System.out.println("普通代码块被调用"); } public static int getNum(){ System.out.println("静态属性被调用"); return 10; }
public String getName(){ System.out.println("普通属性初始化"); return "hello"; } }
|
3:最后调用构造器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| package com;
public class block { public static void main(String[] args) { A a = new A(); } } class A{ public static int num=getNum(); public String name = getName(); public A(){ System.out.println("构造器被调用"); } static{ System.out.println("静态代码块被调用"); } { System.out.println("普通代码块被调用"); } public static int getNum(){ System.out.println("静态属性被调用"); return 10; }
public String getName(){ System.out.println("普通属性初始化"); return "hello"; } }
|
构造器的隐含
构造器的前面隐含了:super()和调用本类中的普通代码块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package com;
public class block { public static void main(String[] args) { B b = new B(); } } class A{ public A() { System.out.println("A的构造器被调用"); } }
class B extends A{ public B() { System.out.println("B的构造器被调用"); } { System.out.println("B类的普通代码块被调用"); } }
|
在这个例子中实例化了B类对象,因此会调用B类的构造器,B类构造器中隐含了super()、调用本类无参代码块,因此实际会先调用B类的父类A的构造器,A的构造器也隐含,因此会先调用A的父类Object的构造器
[warning]