学习总结【2024年7月17日汇总】

【力扣:不同路径问题】

思路:

1.动态规划首先,这是一道非常经典的动态规划题。

2.通式如图,由于机器人只能    向下   或者   向右   移动

所以每一个格子的路径方法只能是由它的上一个格子的路径之和加上左边格子的路径之和

就比如:图中的(i,j)点,就是由(i-1,j)点的路径之和加上(i,j-1)的路径之和

我们可以得到通式:dp[i][j]=dp[i-1][j]+dp[i][j-1];

3.初始化,我们要对第一行和第一列的格子进行初始化,由题目我们可以显而易见得到第一行和第一列的格子只有一种走法。

4.最后,我们基于第一行和第一列的数据,根据动态规划通式,可以得出各个格子的全部路径,然后目标位置的全部路径即可得出。

代码描述:

#include<iostream>
using namespace std;
int dp[101][101];
int F(int n, int m)
{
    int i, j;
    for ( i = 0; i <m; i++)
    {
        dp[i][0]=1;
    }
    for (i = 0; i < n; i++)
    {
        dp[0][i] =1;
    }
    for (i = 1; i < m; i++) {
        for (j = 1; j < n; j++) {
            dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
        }
    }
    return dp[m-1][n-1];
}
int main()
{
    int n, m;
    cin >> n >> m;
    cout<<F(n, m)<<endl;
    return 0;
}

【A - Rook问题】

 1首先输入一个数n,代表测试次数我们用一个while循环即可解决;

2然后就是输入我们要测试的坐标sy,sx其中注意我将sy定为字符,sx定为整形,以便后续操作,然后最重要的一点就是要加将字符sy化为整形数还原1为实际的坐标轴上代表的列数;

3接下来将输入位置的行列都标记为1,其他位置默认为0;

4因为棋盘坐标和实际坐标并不是一 一对应的,所以输出时我将”行“逆反(用9减去原行数)如6->3;5->4;

5以输入坐标为中心点,然后向上,下,左,右四个方向分别做深搜操作,同时将遍历的坐标标为0,直到某一方向深搜到底了,在进行另一方向的深搜;

#include<iostream>
using namespace std;
int a[10][10];
int dx[4] = {-1,1,0,0};//上,下,左,右
int dy[4] = {0,0,-1,1};
void dfs(int m, int n) {
    for (int i = 0; i < 4; i++) {
        int x = m + dx[i];
            int y = n + dy[i];
            if (a[x][y] == 1) {
                char p;
                p = y + 'a' - 1;
                cout << p << 9 - x << endl;
                a[m][n] = 0;
                dfs(x, y);
            }
    }
}
int main()
{
    int n;
    cin >> n;
    while (n--) {
        char sy;
        int sx;
        cin >> sy >> sx;
        sx = 9 - sx;
        int c = sy - 96;//将输入的字母转为数字
 //       
        for (int l = 1; l <= 8; l++)
        {
            a[l][c]=1;
        }
        for (int k = 1; k<= 8; k++)
        {
            a[sx][k]=1;
        }//将输入位置的行列都标记为1,其他位置默认为0;

        int l = 8;
        cout << "  abcdefgh" << endl;
        for (int i = 1; i < 9; i++) {
            cout << l<<" ";
            l = l - 1;
            for (int j = 1; j < 9; j++){
                cout << a[i][j];
                if (j == 8)
                    cout << endl;
            }
        }//将棋盘标记后的样子显示出来;
 ///       

        a[sx][c] = 0;
        for (int i = 0; i <=3; i++) {
            int x = sx + dx[i];
            int y = c + dy[i];
            if (a[x][y] == 1) {
                char b;
                b = y + 'a'-1;//将列数(数字)转为字母              
                cout << b<< 9-x<< endl;//输出时将行逆反(用9减去原行数)如6->3;5->4;
                a[x][y] = 0;
                dfs(x, y);
            }
        }
    }
    return 0;
}

面向对象高级:

1.要理解面向对象思想,我们先要知道什么是对象

2.面向对象就是把构成问题的事物分解成一个个对象,建立对象不是为了实现一个步骤,而是为了描述某个事物在解决问题中的行为。

3.类是面向对象中的一个很重要的概念,因为类是很多个具有相同属性和行为特征的对象所抽象出来的,对象是类的一个实例。

类具有三个特性:封装、继承和多态。

三大特征

封装:核心思想就是“隐藏细节”、“数据安全”,将对象不需要让外界访问的成员变量和方法私有化,只提供符合开发者意愿的公有方法来访问这些数据和逻辑,保证了数据的安全和程序的稳定。所有的内容对外部不可见。
继承:子类可以继承父类的属性和方法,并对其进行拓展。将其他的功能继承下来继续发展 。
多态:同一种类型的对象执行同一个方法时可以表现出不同的行为特征。通过继承的上下转型、接口的回调以及方法的重写和重载可以实现多态。方法的重载本身就是一个多态性的体现。

三大思想

面向对象思想从概念上讲分为以下三种:OOA、OOD、OOP

OOA:面向对象分析(Object Oriented Analysis)

OOD:面向对象设计(Object Oriented Design)

OOP:面向对象程序(Object Oriented Programming )

一、静态static.
 

面向对象编程中很常见的一个关键字static.

static读作静态,可以用来修饰成员变量,也能修饰成员方法。先来static修饰成员变量。

1.1 static修饰成员变量
Java中的成员变量按照有无static修饰分为两种:类变量、实例变量。它们的区别如下图所示:

由于静态变量是属于类的,只需要通过类名就可以调用:类名.静态变量

实例变量是属于对象的,需要通过对象才能调用:对象.实例变量

下面代码(注意静态变量,和实例变量是如何调用的)

来看一下上面代码的内存原理 

最后总结一下

 在实际开发中,如果某个数据只需要一份,且希望能够被共享(访问、修改),则该数据可以定义成类变量来记住

1.2 static修饰成员变量的应用场景
写个需求

需求:系统启动后,要求用于类可以记住自己创建了多少个用户对象

 

第一步:先定义一个User类,在用户类中定义一个static修饰的变量,用来表示在线人数;

public class User{
    public static int number;
    //每次创建对象时,number自增一下
    public User(){
        User.number++;
    }
}
第二步:再写一个测试类,再测试类中创建4个User对象,再打印number的值,观察number的值是否再自增。

public class Test{
    public static void main(String[] args){
        //创建4个对象
        new User();
        new User();
        new User();
        new User(); 
        
        //查看系统创建了多少个User对象
        System.out.println("系统创建的User对象个数:"+User.number);
    }
}
 运行上面的代码,查看执行结果是

1.3 static修饰成员方法
 

成员方法根据有无static也分为两类:类方法、实例方法

有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();
    }
}
static修饰成员方法的内存原理。

1.类方法:static修饰的方法,可以被类名调用,是因为它是随着类的加载而加载的; 所以类名直接就可以找到static修饰的方法
        
2.实例方法:非static修饰的方法,需要创建对象后才能调用,是因为实例方法中可能会访问实 例变量,而实例变量需要创建对象后才存在。  所以实例方法,必须创建对象后才能调用。
以上就是  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;
    }
}
接着可以在任何位置调用MyUtils的createCOde()方法产生任意个数的验证码

//比如这是一个登录界面
public class LoginDemo{
    public static void main(String[] args){
        System.out.println(MyUtils.createCode());
    }
}
//比如这是一个注册界面
public class registerDemo{
    public static void main(String[] args){
        System.out.println(MyUtils.createCode());
    }
}
工具类的使用

在补充一点,工具类里的方法全都是静态的,推荐用类名调用为了防止使用者用对象调用。我们可以把工具类的构造方法私有化。

public class MyUtils{
    //私有化构造方法:这样别人就不能使用构造方法new对象了
    private MyUtils(){
        
    }
    
    //类方法
    public static String createCode(int n){
       ...
    }
}
 

1.5 static的注意事项
 

记住三点

类方法中可以直接访问类成员,不可以直接访问实例成员
实例方法中既可以直接访问类成员,也可以直接访问实例成员
实例方法中可以出现this关键之,类方法中不可以出现this关键字

二、继承机制说明


Java的继承机制是面向对象编程的重要概念之一,它允许一个类(子类)基于另一个类(父类)来构建,并且可以继承父类的属性和方法。下面是关于Java继承机制的一些重要点:

extends关键字:在Java中,通过使用 extends 关键字来建立类之间的继承关系。子类使用 extends 关键字引用父类,这样子类就可以继承父类的特性。

单继承:Java是单继承的,意味着一个类只能继承一个直接的父类。但是可以通过多层继承来间接地继承多个类的特性。

super关键字:子类可以使用 super 关键字来引用父类的成员变量和方法。通过 super
关键字,子类可以调用父类的构造方法、访问父类的属性或者调用父类的方法。

方法重写:子类可以重写(覆盖)父类的方法,以便在子类中提供特定的实现。子类通过提供与父类中相同名称和参数列表的方法来实现方法重写。

访问权限:子类可以访问其父类中的 public 和 protected 成员,但不能直接访问父类中的 private 成员。

继承层次:继承可以形成层次结构,即一个类可以作为另一个类的子类,而这个子类又可以作为另一个类的父类,以此类推。这样的层次结构可以通过继承来实现代码的组织和复用。

抽象类和接口:Java中还有抽象类和接口的概念,它们也是用来实现代码重用和多态性的重要机制。抽象类可以包含抽象方法和具体方法,而接口只包含常量和抽象方法。子类可以通过继承抽象类或者实现接口来实现特定的功能。

继承机制是Java编程语言中的核心概念之一,它使得代码的组织和复用变得更加灵活和方便,同时也提供了多态性的支持,使得代码更具有扩展性和可维护性

三、多态

一、什么是多态

在Java中,多态是面向对象编程中的一个重要概念,它允许不同类型的对象对同一方法进行不同的实现。具体来说,多态性指的是通过父类的引用变量来引用子类的对象,从而实现对不同对象的统一操作。

    例如:狗和猫都是动物,动物共同的行为都有吃这个动作,而狗可以表现为啃骨头,猫则可以表现为吃老鼠。这就是多态的表现,即同一件事情,发生在不同对象的身上,就会产生不同的结果。

二、多态实现的条件

在Java中,要实现多态性,就必须满足以下条件:

    继承关系
    存在继承关系的类之间才能够使用多态性。多态性通常通过一个父类用变量引用子类对象来实现。

    方法重写
    子类必须重写(Override)父类的方法。通过在子类中重新定义和实现父类的方法,可以根据子类的特点行为改变这个方法的行为,如猫和狗吃东西的独特行为。

    父类引用指向子类对象
    使用父类的引用变量来引用子类对象。这样可以实现对不同类型的对象的统一操作,而具体调用哪个子类的方法会在运行时多态决定

例如,下面的案例是根据猫和狗叫的动作的不同,而实现的多态:

class Animal {
    public void sound() {
        System.out.println("动物发出声音");
    }
}

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("狗发出汪汪声");
    }
}

class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("猫发出喵喵声");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog(); // 父类引用指向子类对象
        Animal animal2 = new Cat(); // 父类引用指向子类对象

        animal1.sound(); // 输出:狗发出汪汪声
        animal2.sound(); // 输出:猫发出喵喵声
    }
}

   

class Animal {
    public void sound() {
        System.out.println("动物发出声音");
    }
}

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("狗发出汪汪声");
    }
}

class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("猫发出喵喵声");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Dog(); // 父类引用指向子类对象
        Animal animal2 = new Cat(); // 父类引用指向子类对象

        animal1.sound(); // 输出:狗发出汪汪声
        animal2.sound(); // 输出:猫发出喵喵声
    }
}

在这个示例中,Animal 类是父类,Dog 和 Cat 类是它的子类。通过将父类的引用变量分别指向子类对象,实现了多态性。在运行时,根据引用变量的实际类型来调用相应的子类方法,从而输出不同的声音。


三、重写


3.1 什么是重写

在面向对象编程中,重写(Override)指的是子类重新定义和实现了从父类继承而来的方法,以改变方法的行为。子类通过重写方法可以提供自己特定的实现,使得父类方法的行为在子类对象的身上有不同的表现。

想要理解方法重写,需要知道以下概念:

    继承关系
    重写方法是基于父类和子类之间的继承关系。子类继承了父类的方法,包括方法的名称、参数列表和返回类型。

    方法签名
    重写的方法与父类的方法具有相同的方法签名,即方法的名称、参数列表和返回类型必须一致(当然,如果返回类型的对象本身的类型则可以不同,但是必须要有继承关系)。方法签名不包括方法体。

    @Override注解
    为了明确表明这是一个重写的方法,可以使用 @Override 注解来标记子类中的方法。该注解会在编译时检查是否满足重写条件,如果不满足会报错。

    动态绑定
    通过父类引用变量调用被子类重写的方法时,会根据实际引用的对象类型,在运行时动态绑定到相应的子类方法。

方法重写的规则:

    方法名称、参数列表和返回类型必须与父类中被重写的方法相同。

    子类重写的方法的访问修饰符的权限不能低于父类中被重写方法的访问修饰符权限。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected。

    重写的方法不能抛出比父类中被重写的方法更多或更宽泛的异常。子类中重写的方法可以抛出相同的异常或更具体的异常,或者不抛出异常。
        例如,如果父类的方法声明抛出 IOException,则子类中重写的方法可以抛出 IOException 或 FileNotFoundException,或者不抛出异常,但不能抛出比 IOException 更通用的异常,如 Exception。

    重写的方法必须具有相同的方法体,或者可以进行方法体的扩展。
        子类中重写的方法可以调用父类中被重写的方法,使用 super 关键字。

3.2 重写和重载的区别

    首先回顾重载的实现条件:

        方法名称相同:重载的方法必须具有相同的名称。
        参数列表不同:重载的方法的参数列表必须不同。参数列表可以通过参数的类型、个数或顺序的不同来区分重载方法。
        返回类型可以相同也可以不同:重载的方法可以具有相同的返回类型,也可以具有不同的返回类型。返回类型不是重载方法的区分标准。
        方法所在的类中:重载方法必须定义在同一个类中。
        方法的访问修饰符和异常:重载方法可以具有相同的访问修饰符(如 public、private、protected)和抛出的异常。

重写和重载的区别:

重写(Override)和重载(Overload)是Java中两个不同的概念,它们在方法的处理方式和实现上有所不同。

    重载(Overload)指的是在同一个类中,根据方法的参数列表的不同,定义多个具有相同名称但参数类型或个数不同的方法。重载的方法具有相同的名称,但方法签名不同。

    重写(Override)指的是子类重新定义和实现了从父类中继承的方法。重写的方法具有与父类方法相同的名称、参数列表和返回类型。

下面是重写和重载的区别:

    定义位置:重载方法定义在同一个类中,而重写方法定义在父类和子类之间。

    方法签名:重载方法具有相同的名称,但方法签名(参数类型和个数)不同。重写方法具有相同的名称和方法签名。

    继承关系:重载方法不涉及继承关系,可以在同一个类中定义。重写方法是在子类中对父类方法的重新定义和实现。

    运行时调用:重载方法是根据方法的参数列表的不同进行静态绑定,在编译时确定。重写方法是根据对象的实际类型进行动态绑定,在运行时确定。

    目的:重载方法用于在同一个类中实现相似功能但具有不同参数的方法。重写方法用于子类重新定义父类方法的行为,以适应子类的特定需求。

总结来说,重载是在同一个类中根据参数列表的不同定义多个具有相同名称但参数不同的方法,而重写是子类重新定义和实现了从父类继承的方法。重载方法通过静态绑定在编译时确定调用,重写方法通过动态绑定在运行时确定调用。重载用于实现相似功能但具有不同参数的方法,重写用于改变父类方法的行为以适应子类的需求。
四、向上转型和向下转型
4.1 向上转型

向上转型(Upcasting)是指将一个子类的对象引用赋值给其父类类型的引用变量。这是在面向对象编程中的一种常见操作,用于实现多态性和灵活的对象处理。

在向上转型中,子类对象可以被视为父类对象,可以使用父类类型的引用变量来引用子类对象。这样做的好处是可以以统一的方式处理不同类型的对象,实现代码的灵活性和可扩展性。

向上转型的特点和规则如下:

    子类对象可以隐式地转型为父类对象,不需要任何显式的类型转换操作。

    父类引用变量可以引用子类对象,但通过父类引用变量只能访问到子类对象中定义的父类成员,无法访问子类独有的成员。

    子类对象中重写的方法,在通过父类引用变量调用时,会调用子类中的实现(动态绑定)。

    向上转型是安全的操作,因为子类对象本身就是一个父类对象。

在上述示例中,存在一个继承关系:类 Dog 继承自类 Animal。在 Main 类的 main 方法中,首先创建了一个 Dog 类的对象,并将其赋值给一个 Animal 类型的引用变量 animal,这就是向上转型的过程。通过 animal 引用变量,可以调用 eat() 方法,而在运行时,实际执行的是 Dog 类中重写的 eat() 方法。

需要注意的是,虽然 animal 引用变量的类型是 Animal,但是它指向的是一个 Dog 类的对象,因此可以将其重新转型为 Dog 类型(向下转型),并通过 dog 引用变量访问 Dog 类中独有的成员方法 bark()。

总结起来,向上转型允许将子类对象视为父类对象,以父类类型的引用变量来引用子类对象,实现多态性和灵活的对象处理。

  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值