白亮吖雅黑丫の小站 - java
type: channel
link: https://www.520315.xyz/tag/java/
items: Centos系统下部署Android打包生成APK
items: 万能账号密码--sql注入
items: 带你解惑大厂必会使用的stream流、方法引用
items: Java之Lambda表达式的学习
items: Java之stream流的学习
items: java计算后序表达式
items: 关于JAVA对象之间的显隐式转换问题

Centos系统下部署Android打包生成APK
type: item
date: 2021-11-13T11:44:00+08:00
description: 目录1、安装JDK2、Android SDK安装3、安装gradle4、打包APK在centos环境下，想实现Android程序的编译，只能通过gradle 命令去打包版本apk。如下：1. 安装JDK============JDK下载地址：https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html# 这里使用的是openjdk 1.8.0版本，有需要的话需要到java官网上进行下载对应的JDK版本。 $ yum install java -y # 其他版本JDK的安装方式 $ mv jdk1.8.0_161 /usr/local/ $ ln -s /usr/local/jdk1.8.0_161 /usr/local/jdk $ vim /etc/profile #配置JDK的环境变量 export JAVA_HOME=/usr/local/jdk export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH export CLASSPATH=.$CLASSPATH:$JAVA_HOME/lib:$JAVA_HOME/jre/lib:$JAVA_HOME/lib/tools.jar $ source /etc/profile #重新加载系统环境变量 $ java -version #查看java版本2. Android SDK安装====================# 下载sdk工具包 $ wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip # 创建sdk工具文件夹和解压工具包 $ mkdir -p /opt/android/sdk $ unzip sdk-tools-linux-3859397.zip -d /opt/android/sdk # 使用sdkmanager工具配置构建工具和平台版本 $ cd /opt/android/sdk/tools/bin/ $ ./sdkmanager "build-tools;31.0.0" "platforms;android-31" "platform-tools" $ ./sdkmanager --list #可以查看有哪些版本，自行选择对应的版本 # 增加系统环境变量 $ vim /etc/profile export ANDROID_HOME=/opt/android/sdk PATH=$PATH:$ANDROID_HOME:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools:$ANDROID_HOME/emulator:$ANDROID_HOME/tools/bin $ adb version Android Debug Bridge version 1.0.41 Version 31.0.3-7562133 Installed as /opt/android/sdk/platform-tools/adb3. 安装gradle===============下载地址：https://services.gradle.org/distributions/$ wget https://downloads.gradle-dn.com/distributions/gradle-6.3-all.zip $ mkdir /opt/gradle $ unzip gradle-6.3-all.zip -d /opt/gradle/ $ vim /etc/profile export PATH=$PATH:/opt/gradle/gradle-6.3/bin $ source /etc/profile $ gradle -v ------------------------------------------------------------ Gradle 6.3 ------------------------------------------------------------ Build time: 2020-03-24 19:52:07 UTC Revision: bacd40b727b0130eeac8855ae3f9fd9a0b207c60 Kotlin: 1.3.70 Groovy: 2.5.10 Ant: Apache Ant(TM) version 1.10.7 compiled on September 1 2019 JVM: 1.8.0_201 (Oracle Corporat…

万能账号密码--sql注入
type: item
date: 2021-10-05T16:10:00+08:00
description: 自从上次狗剩被隔壁大娘嚼舌根以后，便怀恨在心，一气之下破解了大妈的农场密码，并偷走了大娘种的菜。狗剩：“隔壁大娘，快去农场看看吧，你菜死了！”￼万能账号密码一、什么是万能账号密码1、万能账号1.1 万能账号的使用2、万能密码2.1 万能密码的使用二、万能账号密码原理剖析1、万能账号原理1.1 注释符1.2 比较运算符2、万能密码原理2.1 注释符总结一、什么是万能账号密码我们平时登录账号时，如果是第一次登录，系统会提示我们注册账号，并将我们注册的账号和密码保存到数据库中。当我们再次登录时，系统会将我们输入的账号和密码和数据库中的数据进行匹配，匹配成功能登录。这就意味着我们需要知道一个已经注册过并且正确的账号和密码才能进行登录，那如果我不小心忘记了我的账号或者密码，或者我压根就不知道账号和密码，还有没有办法登录呢？答案是肯定的，那就是 【万能账号密码】万能账号密码是指 【万能账号】和 【万能密码】，顾名思义，就是可以 【登录任意网站】的账号和密码￼1、万能账号当我们不知道用户的账号并且不知道用户的密码时，可以使用万能账号。万能账号并不是一个真正意义上的账号，它是一种【拥有不同变体的格式】需要注意的是，以下所有万能账号中的 a 可以是自定义的数字或字母，比如 1，2，3，b，c，d【数值型万能账号】a or true #a or 1 #a or 1=1 #a or true -- aa or 1 -- aa or 1=1 -- a【单引号字符型万能密码】a' or true #a' or 1 #a' or 1=1 #a' or true --aa' or 1 -- aa' or 1=1 -- a【双引号字符型万能密码】a" or true #a" or 1 #a" or 1=1 #a" or true -- aa" or 1 -- aa" or 1=1 -- a1.1 万能账号的使用账号输入 【万能账号】， 比如 a or true #密码随便输入，比如 1234562、万能密码当我们知道用户的账号，但不知道用户的密码时，可以使用万能密码万能密码并不是一个真正意义上的密码，而是一个【拥有不同变体的格式】需要注意的是：万能密码中的 admin，必须是真实的用户名【数值型万能密码】admin #admin -- a【单引号字符串型万能密码】admin' #admin' -- a【双引号字符串型万能密码】admin” #admin" -- a2.1 万能密码的使用用户名输入 【万能密码】，比如 admin’ #密码随便输入，比如 123456二、万能账号密码原理剖析一个网络安全意识淡薄的网站，其登录功能的SQL语句大概是下面这个样子select from user where username='user' and password='pass' 11、万能账号原理当我们在登录界面输入 【万能账号】比如 a’ or true # 以后，后端会将我们输入的参数拼接到SQL中，然后去数据库中查询账号和密码，SQL语句大概是下面这样select from user where username='a' or true #' and password='pass' 1由于 # 在SQL中是注释符，注释符后面的内容不起作用，所以真正执行的SQL语句大概是下面这样select from user where username='a' or true 1or true 会使SQL语句恒成立，从而查询出数据库中的所有账号和密码，从而使我们成功登录1.1 注释符除了 # 以外， -- 也是SQL中的注释符，但SQL的语法格式规定--和后面的注释内容必须间隔一个空格，所以这需要使用 a' or 1 -- a 而不是 a' or 1 -- 其原理和 a’ or 1 # 大同小异，拼接到SQL中大概是下面这样select from user where username='a' or true -- a' and password='pass' 1注释后面的内容不生效，真正执行的SQL大概是下面这样select from user where username='a' or true 1SQL语句恒成立，从而登录成功换句话来说，a' or true -- a经过SQL的转化后，结果等价于 a’ or true #1.2 比较运算符SQL中规定，非布尔类型的数据参与比较运算时，会转化为布尔类型再参与运算。比如 or 1 或者 or 1=1 ，会转化为布尔类型的 true 再参与 or 的比较运算，也就是变成 or true ，同样能使条件恒成立，从而登录成功简单来讲就是：a' or 1 # 或者 a' or 1=1 # 等价于 a' or true #2、万能密…

带你解惑大厂必会使用的stream流、方法引用
type: item
date: 2021-07-10T21:44:00+08:00
description: 带你解惑大厂必会使用的 Stream流、方法引用🔥## 前言：带你解惑大厂必会使用的 Lambda表达式、函数式接口带你解惑大厂必会使用的 Stream流、方法引用若对你和身边的朋友有帮助, 点赞! 点赞! 点赞! 评论！收藏! 分享给更多的朋友共同学习交流第三章 Stream流在Java 8中，得益于Lambda所带来的函数式编程，引入了一个全新的Stream概念，用于解决已有集合类库既有的弊端。3.1 引言传统集合的多步遍历代码几乎所有的集合（如Collection接口或Map接口等）都支持直接或间接的遍历操作。而当我们需要对集合中的元素进行操作的时候，除了必需的添加、删除、获取外，最典型的就是集合遍历。例如：public class Demo10ForEach { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("张强"); list.add("张三丰"); for (String name : list) { System.out.println(name); } } }这是一段非常简单的集合遍历操作：对集合中的每一个字符串都进行打印输出操作。循环遍历的弊端Java 8的Lambda让我们可以更加专注于做什么（What），而不是怎么做（How），这点此前已经结合内部类进行了对比说明。现在，我们仔细体会一下上例代码，可以发现：for循环的语法就是“怎么做”for循环的循环体才是“做什么”为什么使用循环？因为要进行遍历。但循环是遍历的唯一方式吗？遍历是指每一个元素逐一进行处理，而并不是从第一个到最后一个顺次处理的循环。前者是目的，后者是方式。试想一下，如果希望对集合中的元素进行筛选过滤：将集合A根据条件一过滤为子集B；然后再根据条件二过滤为子集C。那怎么办？在Java 8之前的做法可能为：这段代码中含有三个循环，每一个作用不同：首先筛选所有姓张的人；然后筛选名字有三个字的人；最后进行对结果进行打印输出。public class Demo11NormalFilter { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("张强"); list.add("张三丰"); List<String> zhangList = new ArrayList<>(); for (String name : list) { if (name.startsWith("张")) { zhangList.add(name); } } List<String> shortList = new ArrayList<>(); for (String name : zhangList) { if (name.length() == 3) { shortList.add(name); } } for (String name : shortList) { System.out.println(name); } } }每当我们需要对集合中的元素进行操作的时候，总是需要进行循环、循环、再循环。这是理所当然的么？不是。循环是做事情的方式，而不是目的。另一方面，使用线性循环就意味着只能遍历一次。如果希望再次遍历，只能再使用另一个循环从头开始。那，Lambda的衍生物Stream能给我们带来怎样更加优雅的写法呢？Stream的更优写法下面来看一下借助Java 8的Stream API，什么才叫优雅：public class Demo12StreamFilter { public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("张无忌"); list.add("周芷若"); list.add("赵敏"); list.add("张强"); list.add("张三丰"); list.stream() .filter(s -> s.startsWith("张")) .filter(s -> s.length() == 3) .forEach(s -> System.out.println(s)); } }直接阅读代码的字面意思即可完美展示无关逻辑方式的语义：获取流、过滤姓张、过滤长度为3、逐一打印。代码中并没…

Java之Lambda表达式的学习
type: item
date: 2020-07-22T11:05:00+08:00
description: Java之Lambda表达式的学习1、背景好吧，其实导师昨天说我昨个写的这个代码还可以简化下（第一版代码请看上一篇学习stream流的博客），可以不用new Comparetor对象（匿名内部类）去写，当时我还没想到应该怎么样去改，今早来上班，开启电脑打开IDEA定位到昨天写的这个地方，发现昨天写的那个比较方法可以简化为利用Integer类自带的compare函数不是更好嘛，反正是提取俩对象中字符串的长度进行对比，利用Integer库自带的compare函数去比较就可以免去自己写三段式判断，代码顿时简化了不少呢。第一次改完后是这样的int labelType = blockList.stream().max(new Comparator<JSONObject>() { @Override public int compare(JSONObject o1, JSONObject o2) { return Integer.compare(o1.getStr("paramet_text").length(),o2.getStr("paramet_text").length()) } }).get().getStr("paramet_text").length();然后呢觉得这块代码是不是还可以进行优化，去除匿名内部类，于是乎脑子里一下窜出了一个想法--“JDK8之后不是出了个Lambda表达式嘛，利用Lambda表达式代替匿名内部类来简化代码不是挺好的嘛”，说干咱就开干！第二次改完代码后是这样的int labelType = blockList.stream().max( (o1, o2) -> Integer.compare(o1.getStr("paramet_text").length(),o2.getStr("paramet_text").length()) ) .get() .getStr("paramet_text").length();最后idea提示我还能继续修改，最终版代码：int labelType = blockList.stream().max( Comparator.comparingInt(o -> o.getStr("paramet_text").length()) ) .get() .getStr("paramet_text").length();最后这版代码是利用Comparator接口中直接比较int值得办法去完成此项功能的。改完后进行测试，返回结果和原来一样，好了，至此也就大功告成了！2、Lambda表达式介绍好了，先说完使用背景下面正式开始对Lambda表达式进行学习、记录。Lambda 表达式也可称为闭包，它是 JDK8 的一个新特性，可以取代大部分的匿名内部类，写出更优雅的 Java 代码，尤其在集合的遍历和其他集合操作中，Lambda 允许把函数作为一个方法的参数（函数作为参数传递进方法中），可以极大地优化代码结构。2.1 语法lambda 表达式的语法格式如下：(parameters) -> expression 或 (parameters) ->{ statements; }语法形式为 () -> {}，其中 () 用来描述参数列表，{} 用来描述方法体，-> 为 lambda运算符 ，读作(goes to)。以下是lambda表达式的重要特征:可选类型声明：不需要声明参数类型，编译器可以统一识别参数值。可选的参数圆括号：一个参数无需定义圆括号，但多个参数需要定义圆括号。可选的大括号：如果主体包含了一个语句，就不需要使用大括号。可选的返回关键字：如果主体只有一个表达式返回值则编译器会自动返回值，大括号需要指定明表达式返回了一个数值。2.2 简单用法/** =================== 先上接口代码 =================== */ /**多参数无返回*/ @FunctionalInterface public interface NoReturnMultiParam { void method(int a, int b); } /**无参无返回值*/ @FunctionalInterface public interface NoReturnNoParam { void method(); } /**一个参数无返回*/ @FunctionalInterface public interface NoReturnOneParam { void method(int a); } /**多个参数有返回值*/ @FunctionalInterface public interface ReturnMultiParam { int method(int a, int b)…

Java之stream流的学习
type: item
date: 2020-07-21T16:47:00+08:00
description: Java之stream流的学习1、学习背景你还在为处理对象数组中的元素而困恼吗?传统写法在对数组中的对象进行操作时，首先需要遍历数组(写for循环)，然后再根据需要对对象中的数据进行相应的操作，你写出来的代码或许是这样的：class Student{ private int age; private String sex; private String name; //get set函数省略 //... ... } ... ... //其他代码省略 List<Student> studenNewtList = new ArrayList<Student>(); //1.筛选出年纪小于30的学生 for (Student student : studentList) { if (student.getAge() < 30) { studenNewtList.add(dish); } } //2.对筛选出的学生进行排序 Collections.sort(studenNewtList, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return Integer.compare(o1.getAge(), o2.getAge()); } }); //3.获取排序后菜肴的名字 List<String> lowStudentName = new ArrayList<>(); for (Student s : studenNewtList) { lowStudentName.add(s.getName()); } return lowStudentName而自从在java8以后，学习stream流操作后，代码有了极大的简化，使用更加快速便捷，不需要再去写繁琐的遍历代码，几行语句即可解决所遇到的问题。简化后的代码如下：return studentList.stream() .filter(s -> s.getAge() < 30) //筛选出年纪小于30的学生 .sorted(comparing(Student::getAge)) //根据学生年纪进行排序 .map(Student::getName) //提取符合条件的学生名字 .collect(Collectors.toList()); //转换为List看过上述代码后是不是感觉自己之前写的代码有多low了！没接触stream前我也是这样的，现在了解stream后再次写代码应该趋于简洁化，以提高工作效率！2、stream介绍流是从支持数据处理操作的源生成的元素序列，源可以是数组、文件、集合、函数。流不是集合元素，它不是数据结构并不保存数据，它的主要目的在于计算。2.1 创建流通过集合生成，应用中最常用的一种List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5); Stream<Integer> stream = integerList.stream();通过数组生成int[] intArr = new int[]{1, 2, 3, 4, 5}; IntStream stream = Arrays.stream(intArr);通过Arrays.stream方法生成流，并且该方法生成的流是数值流【即IntStream】而不是Stream。补充一点使用数值流可以避免计算过程中拆箱装箱，提高性能。Stream API提供了mapToInt、mapToDouble、mapToLong三种方式将对象流【即Stream】转换成对应的数值流，同时提供了boxed方法将数值流转换为对象流通过值生成Stream<Integer> stream = Stream.of(1, 2, 3, 4, 5);通过Stream的of方法生成流，通过Stream的empty方法可以生成一个空流通过文件生成Stream<String> lines = Files.lines(Paths.get("data.txt"), Charset.defaultCharset())通过Files.line方法得到一个流，并且得到的每个流是给定文件中的一行通过函数生成 提供了iterate和generate两个静态方法从函数中生成流iterateStream<Integer> stream = Stream.iterate(0, n -> n + 2).limit(5); iterate方法接受两个参数，第一个为初始化值，第二个为进行的函数操作，因为iterator生成的流为无限流，通过limit方法对流进行了截断，只生成5个偶数generateStream<Dou…

java计算后序表达式
type: item
date: 2019-12-09T14:21:00+08:00
description: java计算后序表达式简介题目要求如下：用二叉树读取前缀表达式，打印该算式的后缀表达式，并求解代码实现TreeNode类：package com.zbl; /** * @Author {zbl} * @Date: 2019/12/09/ 12:15 * @Description */ public class TreeNode<T> { public T data; public TreeNode left; public TreeNode right; TreeNode(T data){ this.data = data; } } BiTree类：package com.zbl; import java.util.LinkedList; import java.util.Queue; /** * @Author {zbl} * @Date: 2019/12/09/ 11:54 * @Description */ public class BiTree<T> { //根结点 protected TreeNode<T> root; protected Queue<T> queue; //构造函数 public BiTree(LinkedList<T> inputList){ root = this.creatBiTree(inputList); queue = new LinkedList<T>(); } //添加结点 public TreeNode creatBiTree(LinkedList<T> inputList){ TreeNode<T> tmp = null; //判空 if(inputList==null || inputList.size()==0) return null; //存值 T data = inputList.removeFirst(); if(data != null){ tmp = new TreeNode(data); tmp.left = this.creatBiTree(inputList); tmp.right = this.creatBiTree(inputList); } //返回根结点 return tmp; } public void PostOrder(){ this.PostOrder(this.root); //换行 System.out.println(); } //后续遍历 protected void PostOrder(TreeNode<T> node){ if(node != null){ PostOrder(node.left); PostOrder(node.right); System.out.print(node.data + " "); //入队 queue.add(node.data); } } public Queue<T> getQueue() { return this.queue; } } 主函数package com.zbl; import java.util.LinkedList; import java.util.Queue; import java.util.Scanner; import java.util.Stack; /** * @Author {zbl} * @Date: 2019/12/09/ 11:54 * @Description */ public class Main { // 前序表达式+-+*3..*1..1..1../1..1..5.. public static void main(String[] args) { // write your code here Scanner scan = new Scanner(System.in); System.out.println("请输入前缀表达式："); String str =scan.next(); LinkedList<Character> list = new LinkedList<>(); for (int i = 0; i <str.length() ; i++) { char c = str.charAt(i); if(c=='.') list.add(null); else list.add(c); } BiTree<Character> tree = new BiTree<>(list); //后续遍历 tree.PostOrder(); //求解 System.out.println(solve(tree)); } public static Double solve(BiTree<Character> tree){ //获取后续表达式 Qu…

关于JAVA对象之间的显隐式转换问题
type: item
date: 2019-07-24T12:55:00+08:00
description: 欢迎移步博主CSDN：CSDN博客简介今天有人问了一个关于JAVA对象之间的显隐式转换问题。为详细解释一下该原理，故此写下本篇博客！最后又顺便写了下该容器的具体实现。具体缘由问Question： 在一个容器里取出来时候 （没有定义泛型）为啥要强转 才能取出来？ 知道索引不能直接取出来吗？答Answer: object对象不能直接赋值给int，不能隐式转换，需要手动写对象类型显式转换，这就像猫一定是动物，但动物却不一定是猫一样。强转弱能使用隐式转换，而弱转强则一定要显示转换JAVA对象之间的显隐式转换：public class MyTest { public static void main(String[] args) { MyTest mytest = new MyTest(); Object obj = new Object(); Animal a = new Animal(); Cat c = new Cat(); System.out.println("obj的类型:" + obj.getClass()); System.out.println("a的类型:" + a.getClass()); System.out.println("c的类型:" + c.getClass()); System.out.println(); //隐式转换 obj = a; a = c; System.out.println("obj的类型:" + obj.getClass()); System.out.println("a的类型:" + a.getClass()); System.out.println("c的类型:" + c.getClass()); System.out.println(); //显式转换 c = (Cat)a; a = (Animal)obj; System.out.println("obj的类型:" + obj.getClass()); System.out.println("a的类型:" + a.getClass()); System.out.println("c的类型:" + c.getClass()); System.out.println(); } } class Animal{ } class Cat extends Animal{ }输出结果：obj的类型:class java.lang.Object a的类型:class test.Animal c的类型:class test.Cat obj的类型:class test.Animal a的类型:class test.Cat c的类型:class test.Cat obj的类型:class test.Animal a的类型:class test.Animal c的类型:class test.Cat注因为在java中Objec类是所有类的超类,Object对象转Integer对象需要使用显式转换，然后Integer赋值给int 类型的a变量，这里会进行拆包。我认为写成下面这样比较好理解int a = (Integer) c.get(0);补全该容器的实现(增删查改)class MyCollection { //定于data对象用于存放数据 private Object[] data; //实际长度 private int size; //容器大小 private int maxSize = 10; public MyCollection(int maxSize) { this.maxSize = maxSize; this.data = new Object[maxSize]; } public MyCollection() { this.data = new Object[maxSize]; } public int getSize() { return this.size; } //根据索引取对象 public Object get(int index) { return this.data[index]; } //增 public void add(int index,Object obj) { if(index > size) { throw new ArrayIndexOutOfBoundsException(); } //扩容 if(index >= maxSize) { Object[] newData = new Object[maxSize + 10]; System.arraycopy(this.data, 0, newData, 0, this.data.length); this.data = newData; this.maxS…