精华内容
下载资源
问答
  • 常用的数据分析方法 一、做大数据分析的三大作用 现状分析、原因分析和预测分析。 二、方法论和方法的区别 方法论是从宏观角度出发,从管理和业务的角度提出的分析框架,指导我们接下来具体分析的方向。 方法是...

    最常用的数据分析方法

    一、做大数据分析的三大作用

    • 现状分析、原因分析和预测分析

    二、方法论和方法的区别

    • 方法论是从宏观角度出发,从管理和业务的角度提出的分析框架,指导我们接下来具体分析的方向
    • 方法是微观的概念,是指我们在具体分析过程中使用的方法

    三、数据分析方法论

    数据分析方法论

    1、PEST分析法

    (1)概念:

    • PEST 为一种企业所处宏观环境分析模型,从政治(Politics)、经济(Economy)、社会(Society)、技术(Technology)四个方面分析内外环境,适用于宏观分析。
      PEST分析法

    (2)注意事项:

    • 四点因素也被称之为“pest有害物”,PEST要求高级管理层具备相关的能力及素养
    • PEST分析与外部总体环境的因素互相结合就可归纳出SWOT分析中的机会与威胁。PEST/PESTLE、SWOT 与 SLEPT 可以作为企业与环境分析的基础工具。

    (3)案例:吉利收购沃尔沃

    2、SWOT分析法

    (1)概念:

    • 优势(Strength)、劣势(Weakness)、机遇(Opportunity)、威胁(Threat)四个方面分析内外环境,适用于宏观分析。
      SWOT分析法

    (2)注意事项:

    • SWOT分析法是用来确定企业自身的竞争优势、竞争劣势、机会和威胁,从而将公司的战略与公司内部资源、外部环境有机地结合起来的一种科学的分析方法。
    • 运用这种方法,可以对研究对象所处的情景进行全面、系统、准确的研究,从而根据研究结果制定相应的发展战略、计划以及对策等。

    (3)案例:

    • 价格或价格决策关系到企业的利润、成本补偿、以及是否有利于产品销售、促销等问题。同4P

    3、5W2H分析法

    (1)概念:

    • Why、When、Where、What、Who、How、How much 7个常见的维度分析问题。广泛用于企业管理和技术活动,对于决策执行性的活动措施也非常有帮助,也有助于弥补考虑问题的疏漏
      5W2H分析法

    (2)注意事项(优势):

    • 检查原产品的合理性
    • 可以准确界定、清晰表述问题,提高工作效率。
    • 有效掌控事件的本质,完全地抓住了事件的主骨架,把事件打回原形思考。
    • 简单、方便,易于理解、使用,富有启发意义。
    • 有助于思路的条理化,杜绝盲目性。有助于全面思考问题,从而避免在流程设计中遗漏项目。

    (3)案例:网游用户的购买行为

    4、4P理论

    (1)概念:

    • 经典营销理论,认为产品(Product)、价格(Price)、渠道(Place)和促销(Promote)是影响市场的重要因素。
      4P理论

    (2)注意事项:

    • 产品(Product):包含有形产品、服务、人员、组织、观念或它们的组合。
    • 价格(Price):包括基本价格、折扣价格、支付期限等。
    • 渠道(Place):是指产品从生产企业流转到用户手上的全过程中所经历的各个环节。
    • 促销(Promotion):是指企业通过销售行为的改变来刺激用户消费,以短期的行为促成消费者增长,吸引其他品牌的用户或导致提前消费来促进销售的增长。

    (3)案例:

    • 价格或价格决策关系到企业的利润、成本补偿、以及是否有利于产品销售、促销等问题。
      公司业务分析

    5、AARRR

    (1)概念:

    • 增长黑客的海盗法则,一种以用户为中心的着眼于转化率的漏斗型的数据收集测量模型,从获取(Acquisition)、激活(Activition)、留存(Retention)、收益(Revenue)和推荐(Referral)5个环节增长。AARRR

    (2)注意事项:

    • 1、AARRR是用户指标,其他业务不能硬套
    • 2、AARRR适用于用户分析,其他分析不能硬套
    • 3、AARRR是五个方面,不是五个指标
    • 4、AARRR是整体设计,不是一视同仁
    • 5、AARRR是有优先级的,不是打地鼠
    • 最好的展开方式是先交代当前业务发展阶段(扩张、稳定、收缩)以及业务的的首要目标(稳增长,促转化,保收入,控成本)

    (3)案例:AARRR

    6、逻辑树

    (1)概念:

    • 又称问题树、演绎树或分解树等
    • 可用于业务问题专题分析

    (2)注意事项:

    • 逻辑树的使用必须遵循以下三个原则:
      • 要素化:把相同问题总结归纳成要素。
      • 框架化:将各个要素组织成框架,遵守不重不漏的原则。
      • 关联化:框架内的各要素保持必要的相互关系,简单而不孤立。
    • 缺点:
      • 涉及的相关问题可能有遗漏,虽然可以用头脑风暴把涉及的问题总结归纳出来,但还是难以避免存在考虑不周全的地方。所以在使用逻辑树的时候,尽量把涉及的问题或要素考虑周全。

    (3)案例:

    • 利润分析中的应用 
      利润分析中的应用

    7、用户行为理论

    (1)概念:

    • 用户使用行为是指用户为获取,使用物品或服务所采取的各种行动,用户对产品首先需要有一个认知、熟悉,然后是试用,再决定是否继续消费使用,最后成为忠诚用户

    (2)注意事项:

    • 可利用用户使用行为理论,梳理网站分析各关键指标之间的逻辑关系.构建符合公司实际业务的网站分析指标体系.

    (3)案例:

    网站分析各关键指标之间的逻辑关系

    8、KANO模型

    (1)概念:

    • 对用户需求分类和排序的有用工具,通过分析用户对产品功能的满意程度,对产品功能进行分级,从而确定产品实现过程中的优先级。
    • 在KANO模型中,根据不同类型的需求与用户满意度之间的关系,可将影响用户满意度的因素分为五类:基本型需求、期望型需求、兴奋型需求(魅力型需求)、无差异需求、反向型需求KANO模型
    • 根据5项功能的better-worse系数值,将散点图划分为四个象限,以确立需求优先级
      在这里插入图片描述

    (2)影响用户满意度因素的解释:

    1)兴奋型需求

    (3)注意事项:

    • KANO模型是一个典型的定性分析模型,一般不直接用来测量用户的满意度,常用于识别用户对新功能的接受度。
    • 帮助企业了解不同层次的用户需求,找出顾客和企业的接触点,挖掘出让顾客满意至关重要的因素。

    (4)案例:

    9、RFM客户价值模型

    (1)概念:

    • RFM模型是针对用户分类的一种模型,模型通过最近消费(Recency)、消费频率(Frequency)、消费金额(Monetary),三大指标将用户分为8大类。三大指标可以变成以下三项:RFM模型三大指标
    • 同时根据每一项的程度不同,把客户分成以下8类。当然可以对数据使用一些分类算法,对客户进行跟精细的分类。客户细分

    (2)注意事项:

    • 针对不同的客户,我们可以进行差异化营销,实现客户价值的最大化。

    (3)案例:

    • 航空行业

    四、分析方法论看数据分析的意义

    • 从数据分析方法论也可得知,数据分析的意义在于将杂乱无章的数据转化为清晰可见的可视图,从而进行精准决策

    五、数据分析的七个方法

    1、趋势分析

    • 趋势分析是最简单、最基础,也是最常见的数据监测与数据分析方法。通常我们在数据分析产品中建立一张数据指标的线图或者柱状图,然后持续观察,重点关注异常值线图
    • 在这个过程中,我们要选定第一关键指标(OMTM,One Metric That Metter),而不要被虚荣指标(Vanity Metrics )所迷惑。
    • 社交类APP为例,如果我们将下载量作为第一关键指标,可能就会走偏;因为用户下载APP并不代表他使用了你的产品。在这种情况下,建议将DAU(Daily Active Users,日活跃用户)作为第一关键指标,而且是启动并且执行了某个操作的用户才能算上去;这样的指标才有实际意义,运营人员要核心关注这类指标。

    2、多维分解

    • 多维分解是指从业务需求出发,将指标从多个维度进行拆分;这里的维度包括但不限于浏览器、访问来源、操作系统、广告内容等等。
    • 为什么需要进行多维拆解?有时候一个非常笼统或者最终的指标你是看不出什么问题来的,但是进行拆分之后,很多细节问题就会浮现出来。
    • 举个例子,某网站的跳出率是0.47、平均访问深度是4.39、平均访问时长是0.55分钟。如果你要提升用户的参与度,显然这样的数据会让你无从下手;但是你对这些指标进行拆解之后就会发现很多思路。

    3、用户分群

    用户分群主要有两种分法:维度和行为组合。

    • 第一种根据用户的维度进行分群,比如从地区维度分,有北京、上海、广州、杭州等地的用户;从用户登录平台进行分群,有PC端、平板端和手机移动端用户。
    • 第二种根据用户行为组合进行分群,比如说每周在社区签到3次的用户与每周在社区签到少于3次的用户的区别,涉及到留存分析。用户分群

    4、用户细查

    • 用户行为数据也是数据的一种,观察用户在你产品内的行为路径是一种非常直观的分析方法。
    • 在用户分群的基础上,一般抽取3-5个用户进行细查,即可覆盖分群用户大部分行为规律。
    • 绝大多数产品都或多或少存在一些反人类的设计或者BUG,通过用户细查可以很好地发现产品中存在的问题并且及时解决。

    5、漏斗分析

    • 漏斗分析是一套流程式数据分析,它能够科学反映用户行为状态以及从起点到终点各阶段用户转化率情况的重要分析模型
    • 漏斗分析模型已经广泛应用于网站用户行为分析APP用户行为分析的流量监控、产品目标转化等日常数据运营与数据分析的工作中。漏斗分析
    • 漏斗分析要注意的两个要点
      • 第一:不但要看总体的转化率,还要关注转化过程每一步的转化率;
      • 第二:漏斗分析也需要进行多维度拆解,拆解之后可能会发现不同维度下的转化率也有很大差异。

    6、留存分析

    • 留存分析是一种用来分析用户参与情况/活跃程度的分析模型,考察进行初始行为的用户中,有多少人会进行后续行为。
    • 这是用来衡量产品对用户价值高低的重要方法。
    • 衡量留存的常见指标有:次日留存率、7日留存率、30日留存率等等。
      留存分析
    • 留存分析可以帮助回答以下问题:
      • 一个新客户在未来的一段时间内是否完成了您期许用户完成的行为?如支付订单等;
      • 某个社交产品改进了新注册用户的引导流程,期待改善用户注册后的参与程度,如何验证?
      • 想判断某项产品改动是否奏效,如新增了一个邀请好友的功能,观察是否有人因新增功能而多使用产品几个月?

    7、A/B测试与A/A测试

    • A/B测试是为了达到一个目标,采取了两套方案,一组用户采用A方案,一组用户采用B方案。通过实验观察两组方案的数据效果,判断两组方案的好坏。在A/B测试方面,谷歌是不遗余力地尝试;对于搜索结果的显示,谷歌会制定多种不同的方案(包括文案标题,字体大小,颜色等等),不断来优化搜索结果中广告的点击率。A/B测试与A/A测试
    • A/B测试之前最好有A/A测试或者类似准备。
    • A/A测试是评估两个实验组是否是处于相同的水平,这样A/B测试才有意义。
    • 其实这和学校里面的控制变量法、实验组与对照组、双盲试验本质一样的。
    展开全文
  • 7 款最常用的 PHP本地测试环境 PHP本地测试本地服务器网站制作必备工 具 服务器 , PHP, 环境 , 工具 , 制作 7 款最常用的 PHP本地测试环境 PHP本地测试本地服务器网站制作必备工具 Wordpress 够流行了吧 它是一个用 ...
  • 一、Android的反混淆工具2 二、一键反编译apk/aar/dex/jar3 ...四、常用的Android逆向分析工具 一、Android的反混淆工具 git clone --recursive https://github.com/CalebFenton/simplify.git ...

    一、Android的反混淆工具2

    二、一键反编译apk/aar/dex/jar3

      (1)、Windows环境配置使用TTDeDroid3

      (2)、Ubuntu环境配置使用TTDeDroid4

    三、Apk脱壳后合并多个dex并使用jadx/JEB/JEB3分析合并后的Apk4

    四、常用的Android逆向分析工具

     

    一、Android的反混淆工具

    git clone --recursive https://github.com/CalebFenton/simplify.git

     

    git submodule update --init --recursive

     

    ./gradlew fatjar

    图片

     

    图片

     

    图片

     

    gradlew.bat fatjar

     

    java -jar simplify/build/libs/simplify-1.2.1.jar -h

     

    java -jar simplify/build/libs/simplify.jar -it 'org/cf/obfuscated' -et 'MainActivity' simplify/obfuscated-app.apk

     

    java -jar simplify/build/libs/simplify-1.2.1.jar -it 'org/cf' G:\workspace\simplify\simplify\src\test\resources\obfuscated-example -o g:\example.dex

     

    二、一键反编译 apk/aar/dex/jar

    git clone https://github.com/tp7309/TTDeDroid.git

     

    (1)、Windows环境配置使用TTDeDroid

    把H:\SecurityAnalysis\TTDeDroid\bin添加到环境变量,如图所示:

    图片

     

    图片

     

    图片

     

    图片

     

    (2)、Ubuntu环境配置使用TTDeDroid

    把export PATH=$PATH:/home/gyp/gyp/SecurityAnalysis/TTDeDroid/bin添加到~/.bashrc中,如图所示:

    图片

     

    图片

     

    vim ~/.bashrc

     

    source ~/.bashrc

     

    chmod a+x /home/gyp/gyp/SecurityAnalysis/TTDeDroid/bin/showjar

     

    showjar test.apk

     

    三、Apk脱壳后合并多个dex并使用jadx/JEB/JEB3分析合并后的Apk

    https://github.com/Simp1er/AndroidSec.git

     

    python3 dex2apk.py -a ****.apk -i dex_unpack/ -o ****-output.apk

    图片

     

    图片

     

    图片

     

    四、常用的Android逆向分析工具

    apktool

    https://bitbucket.org/iBotPeaches/apktool/downloads/

     

    XJad

    https://www.lanzous.com/i2vvdvi

     

    Smali2JavaUI

    https://forum.xda-developers.com/showthread.php?t=2430413

     

    jadx

    https://github.com/skylot/jadx/releases

     

    JEB

    https://www.pnfsoftware.com/

     

    JEB3

    https://www.pnfsoftware.com/blog/jeb3-alpha-is-available/

    https://www.pnfsoftware.com/blog/category/jeb3/

     

    GDA

    http://www.gda.wiki:9090/

     

    IDA

    https://www.hex-rays.com/products/ida/news/

    https://www.hex-rays.com/products/ida/

    https://ida2020.org/

     

    关注公众号,获取更多最新文章

    图片

    展开全文
  • 本文实例讲述了php发送http请求的常用方法。分享给大家供大家参考,具体如下: http请求有get,post。 php发送http请求有三种方式[我所知道的有三种,有其他的告诉我]。 1. file_get_contents();详情见:...
  • title: String类常用方法源码分析 date: 2019-10-24 13:48:58 tags: java categories: java 环境: JDK8 String 先看String类的定义 public final class String implements java.io.Serializable, Comparable<...

    title: String类常用方法源码分析
    date: 2019-10-24 13:48:58
    tags: java
    categories: java

    环境: JDK8

    String

    先看String类的定义

    public final class String
        implements java.io.Serializable, Comparable<String>, CharSequence
    

    可以看到String类被final修饰,因此不能被继承.String类还实现了序列化接口Serializable,可比较的接口Comparable并指定泛型String,该接口必须实现int compareTo方法,最后还实现了字符序列CharSequence的接口,该接口常用的方法如chatAt(int index),length(),toString()等等.

    构造字符串

    String类的无参构造函数

    /**
         * Initializes a newly created {@code String} object so that it represents
         * an empty character sequence.  Note that use of this constructor is
         * unnecessary since Strings are immutable.
         */
    public String() {
            this.value = "".value;
    }
    

    其中value定义:

     /** The value is used for character storage. */
        private final char value[];
    

    该构造函数创建了一个空的字符换并存在字符数组value中.

    再看看一个有参的构造函数:

    /**
         * Allocates a new {@code String} so that it represents the sequence of
         * characters currently contained in the character array argument. The
         * contents of the character array are copied; subsequent modification of
         * the character array does not affect the newly created string.
         *
         * @param  value
         *         The initial value of the string
         */
        public String(char value[]) {
            this.value = Arrays.copyOf(value, value.length);
        }
    
    
    1. 该构造函数指定一个字符数组来创建一个字符序列,是通过Arrays的copyOf方法将字符数组拷贝到当前数组.
      这样当修改字符数组的子串时,不会影响新字符数组.

    下面经过一个简单的测试来验证下

     public static void main(String[] args) {
            char[] c1 = {'a', 'b'};
            char[] c2 = c1;
            for (int i = 0; i < c1.length; i++) {
                if (i==1){
                    c1[1]='c';
                }
            }
            for (char c : c1) {
                System.out.println("c1:"+c);
            }
            for (char c : c2) {
                System.out.println("c2:"+c);
            }
    
        }
    

    结果

    c1:a
    c1:c
    c2:a
    c2:c
    

    由上可知,在c1赋值给c2后,改变了c1中的值c2的值也会随之变化,这显然与我们想要的相悖,所以才会使用拷贝的方式,将c1与c2分开.

    经过以上分析可以看出,下面两个语句是等价的,因为String类底层使用char[]数组来存储字符序列.

    char data[] = {'a', 'b', 'c'};
    String str = new String(data);
    
    1. string.value.length的代码等价于string.length
    public int length() {
            return value.length;
        }
    

    使用字节数组构造一个String

    在Java中,String实例中保存有一个char[]字符数组,char[]字符数组是以unicode码来存储的,String 和 char 为内存形式,byte是网络传输或存储的序列化形式。所以在很多传输和存储的过程中需要将byte[]数组和String进行相互转化。所以,String提供了一系列重载的构造方法来将一个字符数组转化成String,提到byte[]和String之间的相互转换就不得不关注编码问题。

    String(byte[] bytes, Charset charset) 是指通过charset来解码指定的byte数组,将其解码成unicode的char[]数组,够造成新的String。

    这里的bytes字节流是使用charset进行编码的,想要将他转换成unicode的char[]数组,而又保证不出现乱码,那就要指定其解码方式。

    如果我们在使用byte[]构造String的时候,使用的是下面这四种构造方法(带有charsetName或者charset参数)的一种的话,那么就会使用StringCoding.decode方法进行解码,使用的解码的字符集就是我们指定的charsetName或者charset。 我们在使用byte[]构造String的时候,如果没有指明解码使用的字符集的话,那么StringCoding的decode方法首先调用系统的默认编码格式,如果没有指定编码格式则默认使用ISO-8859-1编码格式进行编码操作。主要体现代码如下:

    static byte[] encode(String charsetName, char[] ca, int off, int len)
            throws UnsupportedEncodingException
        {
            StringEncoder se = deref(encoder);
            String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
            if ((se == null) || !(csn.equals(se.requestedCharsetName())
                                  || csn.equals(se.charsetName()))) {
                se = null;
                try {
                    Charset cs = lookupCharset(csn);
                    if (cs != null)
                        se = new StringEncoder(cs, csn);
                } catch (IllegalCharsetNameException x) {}
                if (se == null)
                    throw new UnsupportedEncodingException (csn);
                set(encoder, se);
            }
            return se.encode(ca, off, len);
    }
    

    上面是编码清单,下面是解码清单:

    static char[] decode(String charsetName, byte[] ba, int off, int len)
            throws UnsupportedEncodingException
        {
            StringDecoder sd = deref(decoder);
            String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
            if ((sd == null) || !(csn.equals(sd.requestedCharsetName())
                                  || csn.equals(sd.charsetName()))) {
                sd = null;
                try {
                    Charset cs = lookupCharset(csn);
                    if (cs != null)
                        sd = new StringDecoder(cs, csn);
                } catch (IllegalCharsetNameException x) {}
                if (sd == null)
                    throw new UnsupportedEncodingException(csn);
                set(decoder, sd);
            }
            return sd.decode(ba, off, len);
    }
    

    charAt

    再看charAt(int index)方法源码:

    public char charAt(int index) {
            if ((index < 0) || (index >= value.length)) {
                throw new StringIndexOutOfBoundsException(index);
            }
            return value[index];
    }
    

    该方法返回字符序列中下标为index的字符。并且index的范围:(0,value.length].

    concat

    先看源码:

    public String concat(String str) {
            int otherLen = str.length(); //取得str字符串长度
            if (otherLen == 0) { //如果传入的字符串内容为空,则返回原字符串
                return this;
            }
            int len = value.length; //取得原字符串内容的长度
            char buf[] = Arrays.copyOf(value, len + otherLen); //复制字符串的内容到char数组,并扩展长度
            str.getChars(buf, len); //将str的内容复制到buf数组中,位置从len开始。在这一步完成两个字符串的拼接
            return new String(buf, true); //将buf数组转化为新的String实例并返回
        }
    

    步骤含义基本都在上面,这里着重描述一下getChars方法

    void getChars(char dst[], int dstBegin) {
            System.arraycopy(value, 0, dst, dstBegin, value.length);
        }
    

    可以看出,链接字符换操作实际是字符串的拷贝.最后返回连接成功后的字符串.

    最后是一个特殊的私有包范围类型的构造方法,String除了提供了很多公有的供程序员使用的构造方法以外,还提供了一个包范围类型的构造方法(Jdk 8),我们看一下他是怎么样的:

    String(char[] value, boolean share) {
            // assert share : "unshared not supported";
            this.value = value;
    }
    

    从代码中我们可以看出,该方法和 String(char[] value)有两点区别:

    1. 第一个,该方法多了一个参数: boolean share,其实这个参数在方法体中根本没被使用,也给了注释,目前不支持使用false,只使用true。那么可以断定,加入这个share的只是为了区分于String(char[] value)方法,不加这个参数就没办法定义这个函数,只有参数不能才能进行重载。

    2. 第二个区别就是具体的方法实现不同。

    在这里插入图片描述
    那么也就是说,这个方法构造出来的String和参数传过来的char[] value共享同一个数组。 那么,为什么Java会提供这样一个方法呢?

    首先,我们分析一下使用该构造函数的好处:

    1. 首先,性能好,这个很简单,一个是直接给数组赋值(相当于直接将String的value的指针指向char[]数组),一个是逐一拷贝。当然是直接赋值快了。

    2. 其次,共享内部数组节约内存。

    3. 该方法之所以设置为包范围,是因为一旦该方法设置为公有,在外面可以访问的话,那就破坏了字符串的不可变性。

    subString

    substring有两个重载方法:

    public String substring(int beginIndex) {
            if (beginIndex < 0) {
                throw new StringIndexOutOfBoundsException(beginIndex);
            }
            int subLen = value.length - beginIndex;
            if (subLen < 0) {
                throw new StringIndexOutOfBoundsException(subLen);
            }
            return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
        }
    
    public String substring(int beginIndex, int endIndex) {
            if (beginIndex < 0) {
                throw new StringIndexOutOfBoundsException(beginIndex);
            }
            if (endIndex > value.length) {
                throw new StringIndexOutOfBoundsException(endIndex);
            }
            int subLen = endIndex - beginIndex;
            if (subLen < 0) {
                throw new StringIndexOutOfBoundsException(subLen);
            }
            return ((beginIndex == 0) && (endIndex == value.length)) ? this
                    : new String(value, beginIndex, subLen);
        }
    

    这两个重载方法都是先计算要截取的子串长度,判断边界最后返回调用new String(value, beginIndex, subLen)方法,我们来看一下这个方法:

    public String(char value[], int offset, int count) {
            if (offset < 0) {
                throw new StringIndexOutOfBoundsException(offset);
            }
            if (count <= 0) {
                if (count < 0) {
                    throw new StringIndexOutOfBoundsException(count);
                }
                if (offset <= value.length) {
                    this.value = "".value;
                    return;
                }
            }
            // Note: offset or count might be near -1>>>1.
            if (offset > value.length - count) {
                throw new StringIndexOutOfBoundsException(offset + count);
            }
            this.value = Arrays.copyOfRange(value, offset, offset+count);
    }
    

    offset指第一个匹配的字符序列的索引,count指子串的长度。
    最终该子串会被拷贝到字符数组value中,并且后续的字符数组的修改并不影响新创建的字符串。

    contains

    先看一下源码:

    public boolean contains(CharSequence s) {
            return indexOf(s.toString()) > -1;
    }
    

    可以看出,直接调用indexOf方法:

    public int indexOf(String str) {
            return indexOf(str, 0);
    }
    
      public int indexOf(String str, int fromIndex) {
            return indexOf(value, 0, value.length,
                    str.value, 0, str.value.length, fromIndex);
        }
    
    static int indexOf(char[] source, int sourceOffset, int sourceCount,
                char[] target, int targetOffset, int targetCount,
                int fromIndex) {
            if (fromIndex >= sourceCount) {
                return (targetCount == 0 ? sourceCount : -1);
            }
            if (fromIndex < 0) {
                fromIndex = 0;
            }
            if (targetCount == 0) {
                return fromIndex;
            }
    
            char first = target[targetOffset];
            int max = sourceOffset + (sourceCount - targetCount);
    
            for (int i = sourceOffset + fromIndex; i <= max; i++) {
                /* Look for first character. */
                if (source[i] != first) {
                    while (++i <= max && source[i] != first);
                }
    
                /* Found first character, now look at the rest of v2 */
                if (i <= max) {
                    int j = i + 1;
                    int end = j + targetCount - 1;
                    for (int k = targetOffset + 1; j < end && source[j]
                            == target[k]; j++, k++);
    
                    if (j == end) {
                        /* Found whole string. */
                        return i - sourceOffset;
                    }
                }
            }
            return -1;
        }
    

    首先判断开始索引如果大于源字符串则返回,若目标字符串长度为0返回源字符串长度,否则返回-1.

    然后迭代查找字符,若全部源字符串都找到则返回第一个匹配的索引,否则返回-1.
    所以在public boolean contains(CharSequence s)方法中,若indexOf方法返回-1则返回false,否则返回true。

    equals

    源码:

    public boolean equals(Object anObject) {
            if (this == anObject) {
                return true;
            }
            if (anObject instanceof String) {
                String anotherString = (String)anObject;
                int n = value.length;
                if (n == anotherString.value.length) {
                    char v1[] = value;
                    char v2[] = anotherString.value;
                    int i = 0;
                    while (n-- != 0) {
                        if (v1[i] != v2[i])
                            return false;
                        i++;
                    }
                    return true;
                }
            }
            return false;
    }
    

    该方法首先判断this == anObject ?,也就是说判断要比较的对象和当前对象是不是同一个对象,如果是直接返回true,如不是再继续比较,然后在判断anObject是不是String类型的,如果不是,直接返回false,如果是再继续比较,到了能终于比较字符数组的时候,他还是先比较了两个数组的长度,不一样直接返回false,一样再逐一比较值。

    join

    public static String join(CharSequence delimiter, CharSequence... elements) {
            Objects.requireNonNull(delimiter);
            Objects.requireNonNull(elements);
            // Number of elements not likely worth Arrays.stream overhead.
            StringJoiner joiner = new StringJoiner(delimiter);
            for (CharSequence cs: elements) {
                joiner.add(cs);
            }
            return joiner.toString();
    }
    
    1. StringJoiner 类也是jdk1.8开始加入的通过分隔符或前缀或后缀来构造字符串的,底层是字符序列的拷贝。

    2. requireNonNull方法校验参数不能为空,否则抛异常.源码:

    public static <T> T requireNonNull(T obj) {
            if (obj == null)
                throw new NullPointerException();
            return obj;
    }
    

    ==============================================

    参考文章: https://blog.csdn.net/u011726984/article/details/51326697

    展开全文
  • ArrayList常用方法底层源码分析 数据结构 ArrayList的底层数据结构就是一个数组,数组元素的类型为Object类型,对ArrayList的所有操作底层都是基于数组的。 安全性 对ArrayList进行添加元素的操作的时候是分两个...

    数据结构

    • ArrayList的底层数据结构就是一个数组,数组元素的类型为Object类型,对ArrayList的所有操作底层都是基于数组的。

    安全性

    • 对ArrayList进行添加元素的操作的时候是分两个步骤进行的,即:
      第一步先在object[size]的位置上存放需要添加的元素; 第二步将size的值增加1。
      由于这个过程在多线程的环境下是不能保证具有原子性的,因此ArrayList在多线程的环境下是线程不安全的。
    • 具体举例说明:
      在单线程运行的情况下,如果Size = 0,添加一个元素后,此元素在位置 0,而且Size=1;而如果是在多线程情况下,比如有两个线程,线程 A 先将元素存放在位置0。但是此时 CPU 调度线程A暂停,线程 B 得到运行的机会。线程B也向此ArrayList 添加元素,因为此时 Size 仍然等于 0 (注意哦,我们假设的是添加一个元素是要两个步骤哦,而线程A仅仅完成了步骤1),所以线程B也将元素存放在位置0。然后线程A和线程B都继续运行,都增 加 Size 的值。 那好,现在我们来看看 ArrayList 的情况,元素实际上只有一个,存放在位置 0,而Size却等于 2。这就是“线程不安全”了。
    • 如果非要在多线程的环境下使用ArrayList,就需要保证它的线程安全性,通常有两种解决办法:
      第一,使用synchronized关键字;
      第二,可以用Collections类中的静态方法synchronizedList();对ArrayList进行调用即可。

    继承和实现的类

    • ArrayList继承AbstractList抽象父类;
    • 实现的接口:
      1、List接口(规定了List的操作规范)
      2、RandomAccess(可随机访问)
      3、Cloneable(可拷贝)
      4、Serializable(可序列化)

    主要成员变量

    public class ArrayList<E> extends AbstractList<E>
            implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    {
        // 版本号
        private static final long serialVersionUID = 8683452581122892189L;
        // 缺省容量(初始值)
        private static final int DEFAULT_CAPACITY = 10;
        // 空对象数组
        private static final Object[] EMPTY_ELEMENTDATA = {};
        // 缺省空对象数组
        private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
        // 元素数组
        transient Object[] elementData;
        // 实际元素大小,默认为0
        private int size;
        // 最大数组容量
        private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
        // 数组被修改的次数
        protected transient int modCount = 0;
    }
    

    add()方法

    	 public boolean add(E e) {
            // 给数组容量+1
            ensureCapacityInternal(size + 1);  
            // 在数组位置上添加数据
            elementData[size++] = e;
            return true;
        }
    

    扩容机制

    private void ensureCapacityInternal(int minCapacity) {
        // 判断当前数组是否为空数组
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            // 取当前数组和集合默认容量的最大值
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
    
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        // 如果>0,则扩容
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    private void grow(int minCapacity) {
        // 当前数组长度
        int oldCapacity = elementData.length;
        // 扩容当前数组长度的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 扩容后的容量与minCapacity比对
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // 将就数组数据copy到新数组
        elementData = Arrays.copyOf(elementData, newCapacity);
    }   
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
    

    set()方法

    public E set(int index, E element) {
        // 检查下标是否越界
        rangeCheck(index);
        // 获取原数组位置中的旧值
        E oldValue = elementData(index);
        // 赋予新值
        elementData[index] = element;
        return oldValue;
    }
    
    private void rangeCheck(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
    }
    
    @SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }
    

    remove()方法

     public E remove(int index) {
        // 检查下标是否越界
        rangeCheck(index);
        modCount++;
        // 获取老值
        E oldValue = elementData(index);
    	// 需要移动的元素的数量
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
         // 赋予空值,方便GC回收
        elementData[--size] = null;
        return oldValue;
    }
    

    get()方法

    public E get(int index) {
        // 检查下标是否合法
        rangeCheck(index);
    	// 返回下标处的值
        return elementData(index);
    }
    

    indexOf()方法

    public int indexOf(Object o) {
        // 判断o是否为null
        if (o == null) {
            // 遍历数组,返回第一个元素为空的下标
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;
        } else {
            for (int i = 0; i < size; i++)
                // 找到和o相同的元素,返回下标
                if (o.equals(elementData[i]))
                    return i;
        }
        // 找不到返回-1
        return -1;
    }	
    

    ArrayList的优点

    1. ArrayList底层以数组实现,是一种随机访问模式,因此查找也就是get的时候非常快。
    2. ArrayList在顺序添加一个元素的时候非常方便,只是往数组里面添加了一个元素而已。
    3. 根据下标遍历元素,效率高。
    4. 根据下标访问元素,效率高。
    5. 可以自动扩容,默认为每次扩容为原来的1.5倍。

    ArrayList的缺点

    1. 插入和删除元素的效率不高。
    2. 根据元素值查找元素下标需要遍历整个元素数组,效率不高。
      线程不安全。
    展开全文
  • 数据分析工作中都是有很多的数据分析方法的,我们掌握了数据分析方法以后才能够做好数据分析的工作。那么数据分析的方法都有哪些呢?一般来说,数据分析的方法有PEST分析法、5W2H分析法、逻辑树分析法、4P营销理论、...
  • 做需求分析常用方法

    千次阅读 2019-06-03 19:26:21
    方法论有很多,如: 营销方向理论模型: 4P、用户使用行为、STP理论、...PEST分析法用于对宏观环境分析。宏观环境又称一般环境,是指影响一切行业和企业的各种宏观力量。 主要包括:政治环境、经济环境、社会...
  • 快速安装python及常用数据分析库的方法——使用Anaconda 适用场景: 如果你是习惯使用python的数据分析人员,需要Jupyter notebook 交互式分析环境、需要Pandas、Numpy 等分析库、Matplotlib绘图库,以及spyder IDE...
  • 数据分析需要以营销或管理的理论...4P理论一般用于分析公司整体的经营环境。 用户使用行为模型。用于用户行为研究。 STP理论。 SWOT模型。 二、管理理论模型: PEST模型,即Political政治,Economic经济,Soc...
  • 数据分析是指用适当的统计分析方法对收集来的大量数据进行分析,提取有用信息和形成结论而对数据加以详细研究和概括总结的过程。 2.数据分析发展与组成        数据分析的数学...
  • 数组遍历有很多种方法,虽然不同方法有不同的特性及适用环境,除了普通飞for循环之外,for...in能直接输出数组元素的索引,for...of能直接输出数组元素的值,map则可以直接生成新的数组,forEach则可以遍历修改元祖...
  • 2016年3月21日,凌晨2点多开始QQ邮箱收到几十封测试报警邮件,是在应该内...更糟糕的是正式和测试环境是同一个物理空间,如果是内存溢出,Java heap space,可能导致线上用户大面积出现问题。 打开了手机客户端,试了下
  • systrace使用方法很简单,设置好相应的环境后,进入android-sdk/tools/systrace目录,执行如下命令: python systrace.py --cpu-load --time=10 -o mytrace.html,其中cpu-load是指观察CPU负载,观察时间为10s,输出到...
  • 针对古环境分析中的常用的粘土矿物分析、粒度分析和古水流向分析进行讨论,分析它们各自在古环境分析中的的应用现状和需要注意的问题,论述了古环境分析中易被人们忽视的问题,指出了古环境分析中应根据具体的地质背景,...
  • 初步数据分析方法

    2019-08-19 14:55:45
    看到了一篇关于初级数据分析方法的文章,总结一下: 当在一个公司担任数据分析师的时候,经常会接到各种各样的数据分析需求,在接到需求的时候,我们可以...1)PEST:宏观环境分析。 P - 政治:国家出了哪些相关政策...
  • 主要介绍了smarty中常用方法,较为详细的分析了smarty模板中较为常用方法、属性及环境变量等使用技巧,具有一定参考借鉴价值,需要的朋友可以参考下
  • 写在前面R已经成为当前国际学术界最流行的统计和绘图软件之一,该语言较为简单易学,统计分析功能强大,且具有很强的绘图功能,能够绘制学术出版要求的多种图表.在生物信息学,进化生物学、生态学与环境、经济学、...
  • 环境分析法之:P5S图

    2020-01-25 08:00:24
    环境分析法之:P5S图,叶仁杰,,时下PEST、五力法及 SWOT是最常用环境分析法。然而,这三种方法互有重叠。因此,笔者提出P5S图,是把三者结合。让环境分析更为精简
  • 生产环境中监控JVM性能,分析监控数据,可以知道何时需要JVM调优,可见监控是非常重要的。 JVM的监控范围包括垃圾收集、JIT编译以及类加载。那其中具体都包含哪些?如何监控呢?我们开始探索下吧 二、垃圾收集 监控...
  • 原标题:python数据分析之pandas常用命令整理pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。Pandas 纳入了大量库和一些标准的数据模型 ,提供了高效地操作大型数据集所需的工具。pandas...
  • ? ADB 简介及配置 ? 常用工具指令 ? 问题分析 ? 小技巧 ADB(Android Debug Bridge: ADB 是 Android 提供的一个通用的 调试 工具说白了就是 debug 工具借助这个 工具我们...- 属性 - 高级 - 环境变量 2 在用户环境变量
  • 为明确褐煤煤仓存在的主要危险因素,并实现提前预防控制,分析了HAZOP分析方法常用工艺参数出现的偏差及原因。在阐述褐煤气化反应基本流程和褐煤煤仓基本流程的基础上,结合HAZOP安全分析方法对褐煤煤仓温度、料位、...
  • 原标题:Abaqus中几种常用后处理方法 Abaqus后处理环境中提供了多种进行处理云图和数据的方法,能够快速获得准确直观的分析结果。以路径为主线,分别说明路径建立、曲线生成及输出高质量图片。Abaqus后处理中的路径...
  • 本文对WCDMA系统常用的定位方法进行了分析,包括CELL ID+RTT、OTDOA+IPDL、AGPS和混合定位。CELL ID+RTT实现最为简单,网络侧和UE侧几乎不做任何变化,而且只有一个基站时也能完成定位,但其精度是最低的,因此只能...
  • R是用于统计分析、绘图的语言和操作环境。R是属于GNU系统的一个自由、免费、源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具。
  • 数组是js引用类型中最见的类型之一,掌握数组的各种使用...使用isArray()方法可以最终确定某个值是不是数组,而不管它是在哪个全局执行环境中创建的。 使用方法如下: if(Array.isArray(value)){ //Array就是你的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,197
精华内容 478
关键字:

常用环境分析方法