逆向爬虫34 Java基础二

逆向爬虫34 Java基础二

目的

  • 总结java和之前学过语言之间相似和不同的地方,方便记忆

关于Object ( 上节回顾 )

  • Object可以泛指java中的任何对象 —> 父类可以泛指子类实例化的任何对象

常见数据类型

List系列

  • List类似python中的列表,可以动态扩容,存放任意数量的数据。
  • List是一种接口,其下有两种实现,分别是ArrayList和LinkedList,ArrayList的内存地址是连续的,LinkedList是基于链表形式存放的。
  • 接口是一种约束,约束实现它的类必须包含接口中声明的成员方法。
interface List {
    public void add(Object data);	// 接口中的方法,不写具体的实现,只用于约束。
}
// 类ArrayList实现了接口List,此时这个类就必须有一个add方法。
class ArrayList implements List {
    public void add(Object data) {
        // 将数据data按照连续存储的方法放在内存。
    }
}
// 类LinkedList实现了接口List,此时这个类就必须有一个add方法。
class LinkedList implements List {
    public void add(Object data) {
        // 将数据data按照链表的形式存储
    }
}
List v1 = new ArrayList();
v1.add("一个小黑");
v1.add("麻子");

List v2 = new LinkedList();
v2.add("一个小黑");
v2.add("麻子");
  • List的方法和python中的列表类似,见方法名就就能知道它的含义。List中可以不指定内部存放的数据类型,那么默认存放的是Object类型,可以泛指任何数据类型,这样就和python中的列表很像了。
  • LinkedList的简单用法,ArrayList用法相似,只是底层存储方式不同
import java.util.LinkedList;

public class Hello {
    public static void main(String[] args) {
        LinkedList<String> stringList = new LinkedList<String>();
        stringList.add("一个小黑");   // 在List尾部添加元素
        stringList.push("王二麻子");  // 在List头部添加元素
        System.out.println(stringList.size());  // 输出List长度
        stringList.set(0, "小潮院长");
        for (String tmp : stringList) {
            System.out.println(tmp);    // 遍历输出List每个元素
        }
    }
}
  • 迭代器的用法和python中也类似
import java.util.ArrayList;
import java.util.Iterator;

public class Hello {
    public static void main(String[] args) {
        ArrayList<String> s1 = new ArrayList<String>();
        s1.add("一个小黑");
        s1.add("小潮院长");
        s1.add("Bilibili");

        Iterator<String> it = s1.iterator();
        while (it.hasNext()) {
            String item = it.next();
            System.out.println(item);
        }
    }
}

在这里插入图片描述

  • 上述逆向案例就是将CustomerOperateDraftBean类型的LinkedList转化成迭代器,利用迭代器遍历里面的元素。

Set系列

  • Set类似python中的集合,用于存放不重复的多元素集合。
  • Set是一种接口,其下有两种实现,分别是HashSet和TreeSet,HashSet去重,无序,TreeSet去重,内部默认排序(ascii、unicode)。
  • TreeSet的简单用法,HashSet用法相似,只是一个默认排序,一个无序
import java.util.Iterator;
import java.util.TreeSet;

public class Hello {
    public static void main(String[] args) {
        TreeSet<String> t1 = new TreeSet<String>();
        t1.add("car");
        t1.add("banana");
        t1.add("apple");
        
        Iterator<String> it = t1.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());	// 输出顺序 apple, banana, car
        }
    }
}

在这里插入图片描述

上述逆向案例就是定义了一个TreeSet,然后根据一些条件往里面添加元素,然后根据里面的东西做相应的计算。

Map系列

  • Map类似python中的字典,用于存放键值对。
  • Map是一种接口,其下有两种实现,分别是HashMap和TreeMap,HashMap无序,TreeMap内部默认排序(ascii、unicode)。
  • python里没有排序的字典,但可以通过sorted()函数将字典按键值进行排序,逆向中有时候会从TreeMap中提取键值对,并用’&'连接构成字符串,在python中需要对字典进行排序后,再连接成字符串
d = {
    "aid": 123,
    "xx": 999,
    "wid": 888
}
result = "&".join([f'{key}={d[key]}' for key in sorted(d.keys())])
  • TreeMap的简单用法,HashMap用法相似,只是一个默认排序,一个无序
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

public class Hello {
    public static void main(String[] args) {
        TreeMap<String, String> m1 = new TreeMap<String, String>();
        m1.put("name", "一个小黑");
        m1.put("age", "18");
        m1.put("sex", "男");

        // java中的Map类型不能直接转换为迭代器,必须借助Set
        Set<Map.Entry<String, String>> s1 = m1.entrySet();
        Iterator<Map.Entry<String, String>> it1 = s1.iterator();
        while (it1.hasNext()) {
            Map.Entry<String, String> entry = it1.next();
            String k = entry.getKey();
            String v = entry.getValue();
            System.out.println(k + ": " + v);
        }

        // 利用for循环遍历Map
        for (Map.Entry<String, String> entry : m1.entrySet()) {
            String k = entry.getKey();
            String v = entry.getValue();
            System.out.println(k + ": " + v);
        }
    }
}

在这里插入图片描述

上述逆向案例利用for循环遍历Map中的键值对,添加到StringBuilder对象中,最后进行MD5加密。

在这里插入图片描述

在这里插入图片描述

上述逆向案例定义了一个TreeMap v4对象,往里面添加了很多键值对,最后利用StringBuilder讲键值对连接起来,并去掉最后一个’&'字符。

面向对象相关

构造方法 (重载)

  • Java中,在类里和类名相同的方法叫构造方法,构造方法没有返回值,但可以有多个构造方法,通过参数列表不同进行重载,后期利用frida进行hook的时候,需要注意重载的问题。
class Person {
    // 实例变量
    public String name;
    public int age;

    // 重载构造方法1
    public Person() {
        this.name = "一个小黑";
        this.age = 18;
    }
    // 重载构造方法2
    public Person(String name) {
        this.name = name;
        this.age = 18;
    }
    // 重载构造方法3
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 方便打印输出,调试使用
    public String toString() {
        return this.name + " " + this.age;
    }
}

public class Hello {
    public static void main(String[] args) {
        Person p1 = new Person();
        Person p2 = new Person("小潮院长");
        Person p3 = new Person("小潮院长", 18);
        System.out.println(p1);     // 一个小黑 18
        System.out.println(p2);     // 小潮院长 18
        System.out.println(p3);     // 小潮院长 18
    }
}

静态成员

  • Java中,类里的成员分为静态成员和实例成员(成员可以是方法,也可以是变量),静态成员是和类绑定的,无需实例化对象就可以调用,实例成员必须通过类实例化对象后,通过对象调用。
class Person {
    public static String city = "上海";     // 静态变量
    public String name;                     // 实例变量

    public Person() {
        this.name = "一个小黑";
    }
}

public class Hello {
    public static void main(String[] args) {
        System.out.println(Person.city);    // 静态变量通过类名获取
        Person p1 = new Person();
        System.out.println(p1.name);        // 实例变量通过对象获取
    }
}

继承

  • 和Python不同,Java中的继承只能是单继承,但可以实现多个接口。
class Base {
    ...
}
// 单继承
class Son extends Base {
    ...
}
class Base {
	public void add();
}
class Foo {
	public void plus();
}
// 实现多个接口
class Son implements Base, Foo {
    public void add() {
        
    }
    public void plus() {
        
    }
}
  • Java简单的继承示例
// 父类
class Base {
    public String email;

    public Base(String email) {
        this.email = email;
    }

    public String getSubInfo() {
        return String.format("%s", this.email);
    }
}
// 子类继承父类
class Person extends Base {
    public String name;
    public Integer age;

    public Person(String name, Integer age, String email) {
        super(email);
        this.name = name;
        this.age = age;
    }

    public String getInfo() {
        return String.format("%s-%d-%s", this.name, this.age, this.email);
    }
}

public class Hello {
    public static void main(String[] args) {
        Person p1 = new Person("一个小黑", 18, "xxx@qq.com");
        System.out.println(p1.getInfo());       // 一个小黑-18-xxx@qq.com
        System.out.println(p1.getSubInfo());    // xxx@qq.com
    }
}
  • Java中的父类可以泛指所有的子类,但实际上父类定义的变量取决于后面的构造方法。
  • 如果用父类泛指了子类,那么调用父类和子类中同名且参数列表相同的方法时,会调用实际子类的方法。
  • 如果用父类泛指了子类,那么调用子类中有但父类中没有的方法时,需要强制类型转换成子类对象才可以调用。
// 父类
class Base {
    public String email;

    public Base(String email) {
        this.email = email;
    }

    public String getSubInfo() {
        return String.format("%s", this.email);
    }
}
// 子类继承父类
class Person extends Base {
    public String name;
    public Integer age;

    public Person(String name, Integer age, String email) {
        super(email);
        this.name = name;
        this.age = age;
    }

    public String getSubInfo() {
        return String.format("%s-%d-%s", this.name, this.age, this.email);
    }

    public String getInfo() {
        return String.format("%s-%d-%s", this.name, this.age, this.email);
    }
}

public class Hello {
    public static void main(String[] args) {
        Person p1 = new Person("一个小黑", 18, "xxx@qq.com");
        System.out.println(p1.getSubInfo());    // 一个小黑-18-xxx@qq.com

        Base b1 = new Base("yyy@qq.com");
        System.out.println(b1.getSubInfo());    // yyy@qq.com

        // 父类泛指子类,调用父子类共有的方法时,会调用实际子类的方法
        Base b2 = new Person("小潮院长", 18, "zzz@qq.com");
        System.out.println(b2.getSubInfo());    // 小潮院长-18-zzz@qq.com

        // 父类泛指子类,调用子类中新的方法,需要强制类型转换
        Base b3 = new Person("杜海皇", 18, "ooo@qq.com");
        System.out.println(((Person)(b3)).getInfo());   // 杜海皇-18-ooo@qq.com
    }
}

接口

  • Java中接口可以用来约束实现它的类,也可以用来泛指实现它的类
// 接口
interface IMessage {
    public void send();
}

class Wechat implements IMessage {
    public void send() {
        System.out.println("发送微信");
    }
}

class DingDing implements IMessage {
    public void send() {
        System.out.println("发送钉钉");
    }
}

class Sms implements IMessage {
    public void send() {
        System.out.println("发送短息");
    }
}

public class Hello {
    // 参数用接口,可以泛指实现它的子类
    public static void handler(IMessage v1) {
        v1.send();
    }
    public static void main(String[] args) {
        Wechat v1 = new Wechat();
        DingDing v2 = new DingDing();
        Sms v3 = new Sms();
        handler(v1);    // 发送微信
        handler(v2);    // 发送钉钉
        handler(v3);    // 发送短息
    }
}
  • 逆向的时候如果找到了某个方法声明在一个接口里,那么就需要去找哪些类实现了这个接口。
  • 如果只有一个类实现了接口,那么这个方法就确定在这个类中。
  • 如果有多个类实现了接口,那么就需要从调用的地方顺藤摸瓜,看究竟是哪个对象在调用这个方法,来确定方法的定义处。

抽象

  • Java中的抽象类相当于继承+接口,抽象类中既可以替继承它的子类实现方法,也可以约束继承它的子类,必须定义一些方法,也可以泛指继承它的子类
abstract class Base {
    // 抽象方法 (约束子类中必须有这个方法)
    public abstract void play(String name);

    // 普通方法
    public void stop() {
        System.out.println("Stop");
    }
}

class Son extends Base {
    public void play(String name) {
        System.out.println(String.format("%s is plyaing", name));
    }
}

public class Hello {
    public static void main(String[] args) {
        Base s1 = new Son();	// 抽象类也可以泛指它的子类
        s1.play("一个小黑");    // 一个小黑 is plyaing
        s1.stop();      	// Stop
    }
}

包概念

  • Java中的包其实就是文件夹
src
├── Hello.java
└── utils
    └── Helper.java
  • utils就是一个包
import utils.Helper;

public class Hello {
    public static void main(String[] args) {
        System.out.println(Helper.getInfo());
    }
}
package utils;

public class Helper {
    public static String getInfo() {
        return "一个小黑";
    }
}

类的修饰符

  • public,公共(任何人都能调用包中的类)
  • default,只能在当前包中被调用

类成员修饰符

  • public,公共,所有的只要有权限访问类,类中的public成员都可以被访问
  • private,私有,只允许自己类调用
  • protected,同一个包 或 子类可以访问(即使没有在同一个包内,也可以访问父类中的protected成员)
  • default,只能在同一个包内访问
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值