1.static关键字_静态的
1.1static修饰成员变量
Java中的成员变量按照有无static修饰分为两种:类变量、实例变量。它们的区别如下图所示:
区别:
有static修饰的变量属于类,在内存中只有一份,用类名调用
没有static修饰的变量属于对象,每一个对象都有一份,用对象调用
1.2static修饰成员方法
区别:
有static修饰的方法属于类,在内存中只有一份,用类名调用
没有static修饰的方法属于对象,每一个对象都有一份,用对象调用
代码案例:
//定义一个Student类,在类中定义一个类方法、定义一个实例方法
public class Student{
double score;
//类方法:
public static void printHelloWorld{
System.out.println("Hello World!");
System.out.println("Hello World!");
}
//实例方法(对象的方法)
public void printPass(){
//打印成绩是否合格
System.out.println(score>=60?"成绩合格":"成绩不合格");
}
}
代码测试:
//在定义一个测试类,注意类方法、对象方法调用的区别
public class Test2{
public static void main(String[] args){
//1.调用Student类中的类方法
Student.printHelloWorld();
//2.调用Student类中的实例方法
Student s = new Student();
s.printPass();
//使用对象也能调用类方法(不建议)
s.printHelloWorld();
}
}
1.3static修饰成员方法的内存原理
1.类方法:
static修饰的方法,可以被类名调用,是因为它是随着类的加载而加载的;所以类名直接就可以找到static修饰的方法
2.实例方法:
非static修饰的方法,需要创建对象后才能调用,是因为实例方法中可能会访问实例变量,而实例变量需要创建对象后才存在。所以实例方法,必须创建对象后才能调用。
1.4静态方法的应用_定义工具类
如果一个类中的方法全都是静态的,那么这个类中的方法就全都可以被类名直接调用,由于调用起来非常方便,我们把这样的类就叫做工具类。
代码示例:
public class MyUtils{
public static String createCode(int n){
//1.定义一个字符串,用来记录产生的验证码
String code = "";
//2.验证码是由所有的大写字母、小写字母或者数字字符组成
//这里先把所有的字符写成一个字符串,一会从字符串中随机找字符
String data = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKMNOPQRSTUVWXYZ";
//3.循环n次,产生n个索引,再通过索引获取字符
Random r = new Random();
for(int i=0; i<n; i++){
int index = r.nextInt(data.length());
char ch = data.charAt(index);
//4.把获取到的字符,拼接到code验证码字符串上。
code+=ch;
}
//最后返回code,code的值就是验证码
return code;
}
}
调用方法
public class LoginDemo{
public static void main(String[] args){
//类名直接调用方法
System.out.println(MyUtils.createCode());
}
}
1.5静态代码块和代码块
public class Student {
static int number = 80;
static String schoolName = "doit";
// 静态代码块
static {
System.out.println("静态代码块被执行了~~");
schoolName = "多易多易";
}
{
System.out.println("代码块被执行了~~");
schoolName = "多易多易1";
}
}
调用测试
public class Test {
public static void main(String[] args) {
//调用瞅瞅
System.out.println(Student.number);
System.out.println(Student.number);
System.out.println(Student.number);
System.out.println(Student.schoolName); //
}
}
static的注意事项
静态方法可以直接访问静态的成员变量,但是不能访问非静态的成员变量
非静态方法中,非静态成员变量和静态的都可以访问
静态的方法,不能使用this关键字,但是非静态的方法可以
关于静态代码块重点注意:
静态代码块,随着类的加载而执行,而且只执行一次。
代码块创建一次对象就会执行一次,在静态代码块之后执行
2.继承
2.1什么是继承?
你爹的就是你的,这就是继承,不过你爹的钱,摆在明面上的东西你是能继承过来的,但是你爹的小情人,这是私有的,可不能给你。 阴险一下,哈哈
继承的特点:
子类能继承父类的非私有成员变量和成员方法
继承后的对象创建:
子类的对象由父类和子类共同完成的
代码示例:
//定义一个父类
public class A{
//公开的成员
public int i;
public void print1(){
System.out.println("===print1===");
}
//私有的成员
private int j;
private void print2(){
System.out.println("===print2===");
}
}
//写一个B类,继承A类
//此时B类就拥有了A类(父类)里面所有非私有的成员变量和方法
public class B extends A{
public void print3(){
//由于i和print1是属于父类A的公有成员,在子类中可以直接被使用
System.out.println(i); //正确
print1(); //正确
//由于j和print2是属于父类A的私有成员,在子类中不可以被使用
System.out.println(j); //错误
print2();
}
}
测试类:
public class Test{
public static void main(String[] args){
B b = new B();
//父类公有成员,子类对象是可以调用的
System.out.println(i); //正确
b.print1();
//父类私有成员,子类对象时不可以调用的
System.out.println(j); //错误
b.print2(); //错误
}
}
2.2继承的内存原理
子类对象实际上是由子、父类两张设计图共同创建出来的。所以,在子类对象的空间中,既有本类的成员,也有父类的成员。但是子类只能调用父类公有的成员。
2.3为什么要有继承
说白了,可以提高代码的复用性
观察下面的代码,看看有什么可以优化的地方??
思考:
可以发现:
两个类的很多代码都是一样的,比如name,salary,gender这三个属性是一样的
然后get方法和set方法也是一样的
如果把他们相同的抽取出来一个父类,父类里面写这些属性方法,子类中直接继承过来是不是只要写一份呢?
再看下面的代码:
//定义一个父类
public class Doit {
private String name ;
private double salary;
private String gender;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
}
//定义老师的类继承Doit父类
public class Teacher1 extends Doit{
private String course;
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
}
//定义班主任类继承Doit父类
public class BanZhuRen1 extends Doit{
private int studentNum;
public int getStudentNum() {
return studentNum;
}
public void setStudentNum(int studentNum) {
this.studentNum = studentNum;
}
}
定义测试类
public class Test {
public static void main(String[] args) {
Teacher1 teacher1 = new Teacher1();
teacher1.setCourse("java继承");
teacher1.setName("小江");
teacher1.setSalary(9999.99);
teacher1.setGender("male");
BanZhuRen1 banZhuRen1 = new BanZhuRen1();
banZhuRen1.setStudentNum(20);
banZhuRen1.setName("小江");
banZhuRen1.setSalary(9999.99);
banZhuRen1.setGender("male");
}
}
2.4继承之后成员变量,方法,构造器的特点
思考一下:如果说父类中有一个name成员变量,会被子类继承过来,但是子类中也有一个成员变量叫name,那不就冲突了吗?这种问题怎么解决呢?
成员变量以近的为准,方法以是否重写了为准
案例:
public class Fu {
String name = "父亲大人";
int age = 18;
public void print(){
System.out.println("父亲大人的方法");
}
}
class Zi extends Fu{
String name = "小兔崽子";
public void showName(){
System.out.println(name);
}
@Override
public void print(){
System.out.println("小兔崽子的方法");
}
}
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println(zi.name);//小兔崽子
System.out.println(zi.age);//18
zi.print();//小兔崽子的方法
zi.showName();//小兔崽子
}
}
2.4.1什么是方法的重写
当子类觉得父类方法不好用,或者无法满足父类需求时,子类可以重写一个方法名称、参数列表一样的方法,去覆盖父类的这个方法,这就是方法重写。
示例:
public class A {
public void print1(){
System.out.println("111");
}
public void print2(int a, int b){
System.out.println("111111");
}
}
public class B extends A{
// 方法重写
@Override // 安全,可读性好
public void print1(){
System.out.println("666");
}
// 方法重写
@Override
public void print2(int a, int b){
System.out.println("666666");
}
}
//测试类
public class Test {
public static void main(String[] args) {
// 目标:认识方法重写,掌握方法重写的常见应用场景。
B b = new B();
b.print1();// 666
b.print2(2, 3);//666666
}
}
注意事项:
重写的方法上面,可以加一个注解@Override,用于标注这个方法是复写的父类方法
重写的方法返回值类型,必须与被重写的方法返回值类型一样,或者范围更小
私有方法、静态方法不能被重写,如果重写会报错。
2.5构造器的特点
其实子类的构造器中第一行默认是调用的父类构造器,所以调用的顺序如下图
访问本类成员:
this.成员变量 //访问本类成员变量
this.成员方法 //调用本类成员方法
this() //调用本类空参数构造器
this(参数) //调用本类有参数构造器
访问父类成员:
super.成员变量 //访问父类成员变量
super.成员方法 //调用父类成员方法
super() //调用父类空参数构造器
super(参数) //调用父类有参数构造器
注意:this和super访问构造方法,只能用到构造方法的第一句,否则会报错。
2.6权限修饰符
修饰符 | 在本类中 | 在同一个包下的其他类中 | 在任意包下的子类中 | 在任意包下的其他类中 |
private | √ | |||
默认 | √ | √ | ||
protected | √ | √ | √ | |
public | √ | √ | √ | √ |
代码示例:
测试在本类中:
public class Fu {
// 1、私有:只能在本类中访问
private void privateMethod(){
System.out.println("==private==");
}
// 2、缺省:本类,同一个包下的类
void method(){
System.out.println("==缺省==");
}
// 3、protected: 本类,同一个包下的类,任意包下的子类
protected void protectedMethod(){
System.out.println("==protected==");
}
// 4、public: 本类,同一个包下的类,任意包下的子类,任意包下的任意类
public void publicMethod(){
System.out.println("==public==");
}
public void test(){
//在本类中,所有权限都可以被访问到
privateMethod(); //正确
method(); //正确
protectedMethod(); //正确
publicMethod(); //正确
}
}
测试在一个包下
public class Demo {
public static void main(String[] args) {
Fu f = new Fu();
// f.privateMethod(); //私有方法无法使用
f.method();
f.protectedMethod();
f.publicMethod();
}
}
测试在另外一个包下
public class Zi extends Fu {
//在不同包下的子类中,只能访问到public、protected修饰的方法
public void test(){
// privateMethod(); // 报错
// method(); // 报错
protectedMethod(); //正确
publicMethod(); //正确
}
}
父类不同包下
public class Demo2 {
public static void main(String[] args) {
Fu f = new Fu();
// f.privateMethod(); // 报错
// f.method(); //报错
// f.protecedMethod();//报错
f.publicMethod(); //正确
Zi zi = new Zi();
// zi.protectedMethod();
}
}
最后的注意事项:
java的继承是单继承,不支持多继承,但是支持多级继承
3.多态
所谓的多态,就是拿父类接受子类的对象
class Fu
class Zi extends Fu
//创建一个子类的对象正常需要用Zi这个类型去接收,如果用Fu类型去接收他,这种情况就是多态
Fu zi = new Zi()
3.1多态有啥用?
哎,其实没啥用啦,正常的咱也不写这个代码,哈哈!!!
-
代码重用性:通过多态性,可以在不修改已有代码的情况下,通过扩展已有类的功能来创建新类。这样可以提高代码的重用性,减少重复编写代码的工作量。
-
灵活性和可扩展性:多态性可以让程序具有更好的灵活性和可扩展性。通过接口或抽象类定义统一的方法,然后由不同的子类实现具体的行为。这样,我们可以通过增加新的子类来扩展系统的功能,而不需要修改已有的代码。
-
可替代性和可扩展性:多态性使得我们可以用一个通用的父类类型来引用不同子类的对象,从而实现了接口和实现类之间的可替代性。这样可以提高代码的灵活性和可维护性。
// 定义一个动物类
public class Animal {
public void sayHello(){
System.out.println("怎么叫不知道哇");
}
}
// 定义一个狗类,继承自动物类
class Dog extends Animal {
@Override
public void sayHello() {
System.out.println("汪汪汪");
}
public void shakeTail() {
System.out.println("摇尾巴");
}
}
// 定义一个猫类,继承自动物类
class Cat extends Animal {
@Override
public void sayHello() {
System.out.println("喵喵喵");
}
public void catchMouse() {
System.out.println("捉老鼠");
}
}
public class Test {
public static void main(String[] args) {
Animal animal1 = new Dog();
animal1.sayHello(); // 输出:汪汪汪
Animal animal2 = new Cat();
animal2.sayHello(); // 输出:喵喵喵
}
}
在上面的示例代码中,Animal 类是一个父类,定义了一个方法
sayHello()
。然后通过继承 Animal 类来创建了 Dog 和 Cat 类,它们分别实现了自己的sayHello()
方法,并且还有自己独有的方法shakeTail()
和catchMouse()
。不管创建什么子类的对象都可以用父类来引用,定义起来相对比较方便,并且只要是有类需要用这个方法,都可以直接继承这个父类,重写里面的方法(但是只能调用父类中有的方法)
当然,如果我们需要调用子类特有的方法(如
shakeTail()
和catchMouse()
),则需要将父类的引用强制转换为子类的引用。但是这种做法存在风险,可能会导致运行时异常,因此需要谨慎使用。
3.2父类强制类型转换成子类
问题:用父类的引用指向子类的对象是不能调用子类特有的方法的,怎么解决呢?
public class Animal {
public void sayHello(){
System.out.println("怎么叫不知道哇");
}
}
// 定义一个狗类,继承自动物类
class Dog extends Animal {
@Override
public void sayHello() {
System.out.println("汪汪汪");
}
public void shakeTail() {
System.out.println("摇尾巴");
}
}
// 定义一个猫类,继承自动物类
class Cat extends Animal {
@Override
public void sayHello() {
System.out.println("喵喵喵");
}
public void catchMouse() {
System.out.println("捉老鼠");
}
}
如果将Animal类型向下转换成子类的话,就可以调用了
注意:转型的时候原本是什么类型,才能还原成什么类型
4.final关键字
final是一个关键字,可以用来修饰类,变量,方法
final修饰类:不能被继承
final修饰方法:不能被重写。
final修饰变量:不能修改变量对应的值
被final修饰的类不能被继承
被final修饰的方法不能被重写
被final修饰的变量不能被重新赋值
被final修饰的变量=>常量
一般我们在记录一些几乎不会被修改的变量时会定义成常量,调用起来方便快捷又安全
public class Constant {
//常量: 定义一个常量表示学校名称
//为了方便在其他类中被访问所以一般还会加上public修饰符
//常量命名规范:建议都采用大写字母命名,多个单词之前有_隔开
public static final String SCHOOL_NAME = "多易教育";
public static final String USER_NAME= "root";
public static final String PASSWORD= "123456";
}
//测试调用
public class FinalDemo2 {
public static void main(String[] args) {
//由于常量是static的所以,在使用时直接用类名就可以调用
System.out.println(Constant.SCHOOL_NAME);
System.out.println(Constant.USER_NAME);
System.out.println(Constant.PASSWORD);
}
}