Java学习总结(2021版)---类和对象

类的内部成员

一:属性(成员变量)

成员变量 VS 局部变量

成员变量和局部变量区别

  • 在类中的位置不同
    成员变量:在类中方法外面
    局部变量:在方法或者代码块中,或者方法的声明上(即在参数列表中)
  • 在内存中的位置不同
    成员变量:在堆中(方法区中静态区),成员变量属于对象,对象进堆内存
    局部变量:在栈中,局部变量属于方法,方法进栈内存
  • 生命周期不同
    成员变量:随着对象的创建而存在,随着对象的消失而消失
    局部变量:随着方法的调用或代码块的执行而存在,随着方法的调用完毕或者代码块的执行完毕而消失
  • 初始值
    成员变量:有默认初始值
    局部变量:没有默认初始值,使用前需赋值
  • 注意:
    成员变量和局部变量的重名问题,就近原则;
    可以使用this关键字区分,this.string指的是类中的成员变量,而不是方法内部的。
  • 相同点:
    1.1 定义变量的格式:数据类型 变量名 = 变量值
    1.2 先声明,后使用
    1.3 变量都有其对应的作用域

如何声明

【修饰符】  数据类型  属性名;
【修饰符】  数据类型  属性名 = 初始值;//显式初始化
//如果在声明类时没有显式(手动)给属性赋初始值,那么在创建对象后,这个属性有默认的初始值
byteshortintlong0
floatdouble0.0
char型:0'\u0000',而非'0'(注意:此处0!!!)
boolean型:false
引用数据类型(类、接口、数组):null

封装

在这里插入图片描述

//公共的get/set
public class Student{
    
    
 private String name;
    private int age;
  
 public void setName(String name){
    
    
   this.name = name;
     }
 public String getName(){
    
    
   return name;
  }
  
 public void setAge(int age){
    
    
  this.age = age;
 }
 public int getAge(){
    
    
  return age;
 }
}

二:方法

基本概念

权限修饰符  返回值类型   方法名(形参列表){
    
    
	方法体
}

方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
第一个单词首字母小写,其他单词首字母大写

四类方法

序号 链接
1 无参无返回、无参带返回值、带参无返回值、带参带返回值

返回值类型: 返回值 vs 没返回值

  • 要返回值,指定返回值的类型使用return关键字来返回指定类型的变量或常量:“return 数据”。
  • 没返回值,void来表示,不需要使用return.但是,如果使用的话,只能“return;”表示结束此方法的意思。

特殊方法

静态方法:static

声明格式:权限修饰符 static 返回值类型 方法名(形参列表){
    
    方法体}

静态方法中,只能调用静态的方法或属性
public static void show(){
    
    
 System.out.println("我是一个中国人!");
// 不能调用非静态的结构
// eat();
// name = "Tom";
// 可以调用静态的结构
 System.out.println(Chinese.nation);
 walk();//静态方法
}
  非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
public void eat(){
    
    
 System.out.println("中国人吃中餐");
 //调用非静态结构
 this.info();
 System.out.println("name :" +name);
 //调用静态结构
 walk();
 System.out.println("nation : " + nation);
}

注意
随着类的加载而加载,可以通过"类.静态方法"的方式进行调用
在静态的方法内,不能使用this关键字、super关键字,因为不需要实例就可以访问static方法

抽象方法:abstract

声明一个方法但不提供实现,该方法的实现由子类提供

声明格式:【修饰符】 abstract 返回值类型  方法名(形参列表);

注意

  • 抽象方法只有方法的声明,没方法体
  • 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
  • 若子类重写了父类中的所有抽象方法后,此子类方可实例化
  • 若子类没重写父类中的所有抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

方法举例

方法重载

后续整理

方法重写

后续整理

方法的递归

递归方法:一个方法体内调用它自身
// 例1:计算1-n之间所自然数的和
 public int getSum(int n) {
    
    // 3

  if (n == 1) {
    
    
   return 1;
  } else {
    
    
   return n + getSum(n - 1);
  }

 }

 // 例2:计算1-n之间所自然数的乘积:n!
 public int getSum1(int n) {
    
    

  if (n == 1) {
    
    
   return 1;
  } else {
    
    
   return n * getSum1(n - 1);
  }

 }
 
 //例3:已知一个数列:f(0) = 1,f(1) = 4,f(n+2)=2*f(n+1) + f(n),
 //其中n是大于0的整数,求f(10)的值。
 public int f(int n){
    
    
  if(n == 0){
    
    
   return 1;
  }else if(n == 1){
    
    
   return 4;
  }else{
    
    
//   return f(n + 2) - 2 * f(n + 1);
   return 2*f(n - 1) + f(n - 2);
  }
 }

 //例4:斐波那契数列
 ......
 //例5:汉诺塔问题
 ......
 //例6:快排
......

可变形参

在这里插入图片描述

举例:
public void show(int i){
    
    
  
 }
 
 public void show(String s){
    
    
  System.out.println("show(String)");
 }
 
 public void show(String ... strs){
    
    
  System.out.println("show(String ... strs)");
  
  for(int i = 0;i < strs.length;i++){
    
    
   System.out.println(strs[i]);
  }
 }、

调用时:
  test.show("hello");
  test.show("hello","world");
  test.show();
  
  test.show(new String[]{
    
    "AA","BB","CC"});

方法参数传递

在这里插入图片描述

三:构造器(构造方法)

如何声明

1)无参构造
【修饰符】 构造器方法名(){
    
    
 方法体
}2)有参构造
【修饰符】 构造器方法名(形参列表){
    
    
 方法体
}

特点

A:构造器方法名必须与类名相同
B:构造器没有返回值类型
C:构造器可以重载
D:任何类中都有构造器,如果没有显式/手动声明构造器,编译器将自动添加一个默认的无参构造器
E:如果显式/手动声明了任何一个构造器,编译器将不再自动添加默认的无参构造

作用

在这里插入图片描述

四:代码块

静态代码块

在这里插入图片描述

  • 内部可以输出语句
  • 随着类的加载而执行,而且只执行一次
  • 作用:初始化类的信息
  • 如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行(一般定义一个即可!!多个代码块可以合并成一个)
  • 静态代码块的执行要优先于非静态代码块的执行
  • 静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构

非静态代码块

在这里插入图片描述

  • 内部可以输出语句
  • 随着对象的创建而执行
  • 每创建一个对象,就执行一次非静态代码块
  • 作用:可以在创建对象时,对对象的属性等进行初始化
  • 如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行(一般定义一个即可!!多个代码块可以合并成一个)
  • 非静态代码块内可以调用静态的属性、静态的方法,或非静态的属性、非静态的方法

执行特点和加载顺序

  • 执行特点:静态代码块(只执行一次)–》构造块(每次创建对象) --》构造器(每次创建对象)
  • 加载顺序:总结:由父及子,静态先行
    • 涉及到父类、子类中静态代码块、非静态代码块、构造器的加载顺序

五:内部类

在这里插入图片描述

根据声明的位置不同

在这里插入图片描述

成员内部类

  • 如何声明:
【修饰符】  class   外部类{
    
    
          【修饰符】  class  内部类{
    
    
           }
}
  • 如何使用:
    (1)在外部类中使用内部类

    • 除了在外部类的静态成员中,不能直接使用内部类
    • 外部类不允许直接访问非静态内部类中的实例变量。如需访问,必须显式创建内部类对象后才能用该对象访问

    (2)在外部类的外面使用内部类

    • 它需要外部类的对象,才能获得内部类的对象等
示例一:
class  Outer{
    
    
 class Inner{
    
    
 }
}
//使用
Outer.Inner  inner = new Outer().new Inner();
  
Outer out = new Outer();
Outer.Inner  inner = out.new Inner();

示例二:
class Outer{
    
    
  class Inner{
    
    
  }
  
  public Inner getInner(){
    
    
   return new Inner();
  }
  
}
//使用 
Outer out = new Outer();
Outer.Inner in = out.getInner();

示例三:
class Outer{
    
    
 class Inner{
    
    
 }
} 
//继承 Inner
MyClass需要调用Inner的构造器
而调用Inner的构造器,需要外部类Outer的对象
  
class MyClass extends  Outer.Inner{
    
    
  public MyClass(Outer out){
    
    
   out.super();
  }
  
}

(3)在内部类中使用外部类的成员

  • 没有限制,都能用,包括静态的,包括私有的

其他特点:

在这里插入图片描述

静态内部类

如何声明:

【修饰符】  class   外部类{
    
    
          【修饰符】static  class  内部类{
    
    
           }
}1)需要在内部类中声明静态成员,那么这个内部类必须是static2)需要在外部类的静态成员中使用这个内部类,那么这个内部类也必须是static

如何使用:
(1)在外部类中使用:没有限制
(2)在外部类的外面

示例一:
class Outer{
    
    
 static class Inner{
    
    
   public void test(){
    
    
   }
 }
}
  
//如何调用test()
(1)test()看,它不是静态的,因此需要Inner的对象  
(2)Inner在Outer里面,而Inner又是static修饰
  
Outer.Inner  in = new Outer.Inner();
in.test();
  
示例二:  
class Outer{
    
    
  
  
   static class Inner{
    
    
   public static void test(){
    
    
   }
  }
}
  
//使用test()  
(1)test(),是static修饰符,说明不需要Inner对象
(2)看Inner是static修饰,也不需要外部类的对象
  
Outer.Inner.test();

(3)在内部类中使用外部类的成员

  • 在静态内部类中,不能使用外部类的非静态成员
  • 其他的成员可以直接使用,包括私有的

其他特点
- (1)静态的内部类,可以使用权限修饰符 4种
- (2)静态的内部类可以包含静态的成员
- (2)静态的内部类可以包含静态的成员

局部内部类

如何声明:

【修饰符】 class 外部类{
    
    
       【修饰符】  返回值类型  方法名(形参列表){
    
    
                     class   内部类名{
    
    
                     }
        }
}

如何使用:

在这里插入图片描述

其他特点
- (1)不能使用public,protected,private,static这些成员修饰符
- (2)局部内部类中,也不能包含静态成员的
- (3)局部内部类也有自己的字节码文件:外部类$编号内部类.class

匿名内部类

如何声明

【修饰符】 class 外部类{
    
    
       【修饰符】  返回值类型  方法名(形参列表){
    
    
                    new  父类/父接口(){
    
    
                                //内部类的成员
                   }
        }
}
注意:此处,父类要注意是否有无参构造

如何使用
(1)使用父类的多态引用使用它对象

  • 只能调用父类中声明过的方法
package com.atguigu.review;
//在main中,写一个Father的匿名内部类的对象
public class TestNiMing {
    
    
 public static void main(String[] args) {
    
    
  Father f = new Father("尚硅谷"){
    
    
  
   /*@Override
   public String getInfo() {
    return "内部类的示例:" + getInfo();//java.lang.StackOverflowError
   }*/
  
   @Override
   public String getInfo() {
    
    
    return "内部类的示例:" + super.getInfo();
   }
  
   public void method(){
    
    
    System.out.println("匿名内部类自己的方法");
   }
  
  };
  
  System.out.println(f.getInfo());
//  f.method();//无法访问
 }
}
class Father{
    
    
 private String info;
  
 public Father(String info) {
    
    
  super();
  this.info = info;
 }
  
 public String getInfo() {
    
    
  return info;
 }
  
 public void setInfo(String info) {
    
    
  this.info = info;
 }
  
}

(2)本态引用调用方法

  • 可以调用父类的方法,也可以调用子类自己的方法
 public static void main(String[] args) {
    
    
  //父类是Object,使用匿名内部类,声明一个方法void fun(),并调用
  new Object(){
    
    
   public void fun(){
    
    
    System.out.println("匿名内部类的方法");
   }
  }.fun();
 }

(3)作为方法的实参

package com.atguigu.review;
  
import java.util.Arrays;
import java.util.Comparator;
  
public class TestLocal3 {
    
    
  
 public static void main(String[] args) {
    
    
  Dog[] dogs = new Dog[3];
  dogs[0] = new Dog(7.8);
  dogs[1] = new Dog(5.8);
  dogs[2] = new Dog(9.8);
  
  Arrays.sort(dogs, new Comparator(){
    
    
  
   @Override
   public int compare(Object o1, Object o2) {
    
    
    Dog d1 = (Dog) o1;
    Dog d2 = (Dog) o2;
    if(d1.getWeight() > d2.getWeight()){
    
    
     return 1;
    }else if(d1.getWeight() 
     return -1;
    }
    return 0;
   }
  
  });
 }
  
}
class Dog{
    
    
 private double weight;
  
 public Dog(double weight) {
    
    
  super();
  this.weight = weight;
 }
  
 public double getWeight() {
    
    
  return weight;
 }
  
 public void setWeight(double weight) {
    
    
  this.weight = weight;
 }
  
}

其他特点

在这里插入图片描述

面向对象三大特征

封装性

封装两个方面的含义:把该隐藏的隐藏起来,把该暴露的暴露出来。这两个方面都需要通过使用Java提供的访问控制符来实现。
Java提供了3个访问控制符:private、缺省、protected和public,

在这里插入图片描述
关于访问控制符的使用,存在如下几条基本原则。

➢ 类里的绝大部分成员变量都应该使用private修饰,只有一些static修饰的、类似全局变量的成员变量,才可能考虑使用public修饰。除此之外,有些方法只用于辅助实现该类的其他方法,这些方法被称为工具方法,工具方法也应该使用private修饰。
➢ 如果某个类主要用做其他类的父类,该类里包含的大部分方法可能仅希望被其子类重写,而不想被外界直接调用,则应该使用protected修饰这些方法。
➢ 希望暴露出来给其他类自由调用的方法应该使用public修饰。因此,类的构造器通过使用public修饰,从而允许在其他地方创建该类的实例。因为外部类通常都希望被其他类自由使用,所以大部分外部类都使用public修饰。

  • 广义的封装

在这里插入图片描述

  • 狭义的封装

在这里插入图片描述

继承

在这里插入图片描述

多态

  • 多态的作用:代码更灵活

表现
(1)方法的多态性:方法的重写

(2)对象的多态性

对象的多态性:父类的引用指向子类的对象
 Person p2 = new Man();
 //多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法 ---虚拟方法调用
 p2.eat();
 p2.walk();

多态的应用
(1)多态参数

方法声明的形参类型为父类类型,可以使用子类的对象作为实参调用该方法 
public class Test {
    
     
public void method(Person e) {
    
     //Person e = new Student()
 e.getInfo(); 
} 
public static void main(Stirng args[]) {
    
     
 Test t = new Test(); 
 Student m = new Student(); 
 t.method(m); // 子类的对象m传送给父类类型的参数e 
} 
}

(2)多态数组

public static void main(String[] args) 

(3)多态属性

一个引用类型变量如果声明为父类的类型,但实际引用的是子类 
对象,那么该变量就不能再访问子类中添加的属性和方法 
Student m = new Student(); 
m.school = “pku”; //合法,Student类有school成员变量 
Person e = new Student(); 
e.school = “pku”; //非法,Person类没有school成员变量 
属性是在编译时确定的,编译时e为Person类型,没有school成员变量,因而编 
译错误 

数据类型的转换

  • 向上转型

在这里插入图片描述

  • 向下转型
    有了对象的多态性以后,内存中实际上是加载了子类特有的属性和方法的,但是由于变量声明为父类类型,导致编译时,只能调用父类中声明的方法。子类特有的方法不能调用

如何才能调用子类特的属性和方法?使用向下转型(强制转换)

  • 子类类型 变量 = (子类的类型)父类的变量;
    在这里插入图片描述
public class Test {
    
     
public void method(Person e) {
    
     // 设Person类中没有getschool() 方法 
  // System.out.pritnln(e.getschool()); //非法,编译时错误 
  if (e instanceof Student) {
    
     
    Student me = (Student) e; // 将e强制转换为Student类型 
    System.out.pritnln(me.getschool()); 
    } 
} 
}

关键字的使用

this:表示当前对象

(1)this.属性/this.方法

  • 在类的方法中,我们可以使用"this.属性"或"this.方法"的方式
  • 在类的构造器中,我们可以使用"this.属性"或"this.方法"的方式,
  • 在某个方法中把this作为返回值,则可以多次连续调用同一个方法,从而使代码更加简洁。

(2)this调用构造器

  • ① 我们在类的构造器中,可以显式的使用"this(形参列表)"方式,调用本类中指定的其他构造器
  • ② 构造器中不能通过"this(形参列表)"方式调用自己
  • ③ 如果一个类中有n个构造器,则最多有 n - 1构造器中使用了"this(形参列表)"
  • ④ 规定:"this(形参列表)"必须声明在当前构造器的首行
  • ⑤ 构造器内部,最多只能声明一个"this(形参列表)",用来调用其他的构造器

super:表示父类的引用

(1)super.属性/super.方法

我们可以在子类的方法或构造器中。通过使用"super.属性"或"super.方法"的方式,
显式的调用父类中声明的属性或方法。但是,通常情况下,我们习惯省略"super."

  • 特殊情况:当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显式的使用"super.属性"的方式,表明调用的是父类中声明的属性。
  • 特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显式的使用"super.方法"的方式,表明调用的是父类中被重写的方法。

(2)构造器:super()或super(实参列表)
super调用构造器:
1:我们可以在子类的构造器中显式的使用"super(形参列表)"的方式,调用父类中声明的指定的构造器
2:"super(形参列表)"的使用,必须声明在子类构造器的首行!
3: 我们在类的构造器中,针对于"this(形参列表)"或"super(形参列表)“只能二一,不能同时出现
4:在构造器的首行,没显式的声明"this(形参列表)“或"super(形参列表)”,则默认调用的是父类中空参的构造器:super()
5:在类的多个构造器中,至少一个类的构造器中使用了"super(形参列表)”,调用父类中的构造器

static:静态的

  • static相当于一个标志,有static修饰的成员属于类本身,没有static修饰的属于该类的实例
  • 修饰属性、方法、代码块、内部类

final:最终的

在这里插入图片描述

instanceof:

  • 表示某个对象是否是本类或本类的子类的对象

extends:表示继承

抽象:abstract

abstract class  几何图形类{
    
    
 public abstract double getArea();
}
  
classextends 几何图形类{
    
    
 private double 半径;
    public double getArea(){
    
    
  return Math.PI * 半径 * 半径;
 }
}
  
class  矩形  extends 几何图形类{
    
    
 private double;
 private double;
    public double getArea(){
    
    
  return*;
 }
}
  
原因:
(1)从逻辑角度
几何图形类中,应该包含所有几何图形共同的特征
那么所有几何图形,就应该包含  “获取面积”的功能
(2)语法角度
通过“几何图形”类对圆对象,矩形对象等的多态引用,
应该是可以调用“获取面积”的方法,如果父类中没有声明该方法,
就无法调用,无法实现多态引用

抽象类
在父类中明确子类应该包含某些方法,但是在父类中又不能给出具体的实现,父类中只能把这个方法声明为抽象方法

格式【修饰符】 abstract class 抽象类的名称{
    
    
 类的成员列表
}
abstract class A {
    
    
 abstract void m1();
 public void m2() {
    
    
  System.out.println("A类中定义的m2方法");
  } 
 }

class B extends A {
    
    
 void m1() {
    
    
  System.out.println("B类中定义的m1方法");
  } 
 }

public class RecursionTest {
    
    
 public static void main(String args[]) {
    
    
  A a = new B();
  a.m1();
  a.m2();
  } 
 }
编译结果:
B类中定义的m1方法
A类中定义的m2方法

抽象方法

【修饰符】 abstract 返回值类型  方法名(形参列表);
  • 声明一个方法但不提供实现,该方法的实现由子类提供
  • 抽象方法只有方法的声明,没方法体
  • 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。
  • 若子类重写了父类中的所的抽象方法后,此子类方可实例化
  • 若子类没重写父类中的所的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

抽象类的应用
(1)模板设计模式:在软件开发中实现一个算法时,整体步骤很固定、通用,这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来,供不同子类实现。这就是一种模板模式

abstract class Template{
    
    
 
 //计算某段代码执行所需要花费的时间
 public void spendTime(){
    
    
  
  long start = System.currentTimeMillis();//开始时间  
  this.code();//不确定的部分、易变的部分
  
  long end = System.currentTimeMillis();//结束时间
  
  System.out.println("花费的时间为:" + (end - start));
  
 }
 
 public abstract void code();
 
}

class SubTemplate extends Template{
    
    

 @Override
 public void code() {
    
    
  
  for(int i = 2;i <= 1000;i++){
    
    
   boolean isFlag = true;
   for(int j = 2;j <= Math.sqrt(i);j++){
    
    
    
    if(i % j == 0){
    
    
     isFlag = false;
     break;
    }
   }
   if(isFlag){
    
    
    System.out.println(i);
   }
  }

 }
 
}

package:包

在这里插入图片描述

设计模式

单例设计模式

特征
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例。
私有化类的构造器/避免在类的外面调用构造器造对象!并且类内部需要new一个对象
形式:
1:懒汉式:
2:饿汉式:
3:枚举式:
要点:

  • 构造器私有化
  • 在单例类中创建这个唯一的对象

模板设计模式

特征
在父类中能确定某个功能的整体的算法结构,但是对于其中的某个步骤,在父类中无法确定,要延迟到子类中去实现,这个时候就可以通过模板设计模式。属于抽象类的应用

计算任意一段代码或功能的运行时间
  
//父类:确定算法结构
abstract class  SuperClass{
    
    
  
 public final long getTime(){
    
    
  //1、获取开始时间
  long start = System.currentTimeMillis();
  
  //2、运行要计算时间的代码
  run();
  
  //3、获取结束时间
  long end = System.currentTimeMillis();
  
  //4、计算
  return end - start;
 }
  
 protected  abstract void run();
}
  
class SubClass extends SuperClass{
    
    
 protected  void run(){
    
    
  //要测试时间的代码
 }
}

工厂设计模式

目的:使得使用者与创建者分离,把创建某些接口的实现类对象交给工厂来做

简单工厂模式

优点:代码简洁
缺点:当增加新产品时,需要修改工厂方法,违反了“对修改关闭,对扩展开放”的原则

//1、所有的要创建的对象,都是符合某个标准的
interface  Car{
    
    
 void run();
}
  
class BMW  implements Car{
    
    
 public void run(){
    
    
  .... 
     }
}
  
class Benz  implements Car{
    
    
 public void run(){
    
    
  .... 
     }
}
  
//2、设计一个工厂类,用来创建各种各样的Car的实现类的对象
class CarFactory{
    
    
 public  static Car getCar(String name){
    
    
   if("宝马".equals(name)){
    
    
    return new BMW();
   }else if("奔驰".equals(name)){
    
    
    return new Benz();
   }
   return null;
 }
}
  

工厂方法模式

优点:如果增加新产品,只需要增加对应的工厂即可,不需要修改原来的代码
缺点:类太多,代码复杂

//1、所有的要创建的对象,都是符合某个标准的
interface  Car{
    
    
 void run();
}
  
class BMW  implements Car{
    
    
 public void run(){
    
    
  .... 
     }
}
  
class Benz  implements Car{
    
    
 public void run(){
    
    
  .... 
     }
}
  
//2、每一种产品都自己的工厂生产
//所有的工厂就有共同的特征
interface Factory{
    
    
 Car getCar();
}
class BMWFactory implements Factory{
    
    
 public BMW getCar(){
    
    
   return new BMW();
 }
}
class BenzFactory implements Factory{
    
    
 public Benz getCar(){
    
    
   return new Benz();
 }
}

抽象工厂模式

代理模式

猜你喜欢

转载自blog.csdn.net/m0_51755061/article/details/113274065