Android 内功心法(番外)——写在设计模式前,面对对象编程基础

我写的一系列“Android 内功心法”着重讲到android中经常使用的设计模式。那么如果有些程序员刚刚接触设计模式,那就有必要确定一下自己面对对象编程的基础是否牢固了。

因为这直接关系到你阅读设计模式的速度和理解质量。

接下来我将简单介绍java中面对对象编程的一些基础知识。

1,类和修饰符

public class ClassTest{
    public ClassTest{
    }
    public void test(){
    }
}

其中类的定义是以“class”来决定的。class关键字就表示类。

类的命名规范“骆驼命名法”,首字母大写,如果名字由多个单词,则每个单词首字母大写。

“public ”则是修饰符。

public 代表所有包的类都可以访问。(公有)

protected 代表同包下的类可以访问。

private 代表只能当前类才可以访问。(私有)

如何使用类中的方法呢?

若想使用就要”实例化“这个类。实例化类用到关键字”new“

ClassTest classTest;
classTest=new ClassTest();

2,构造方法

也可以称之为”构造函数“。对类初始化的方法。和类同名,没有返回返回值,不需要”void“。在类被实例化的时候自动被调用。

public class ClassTest{
    public ClassTest{//构造方法
    }
}

所有的类都有构造方法,如果程序员不写,系统也会默认生成一个空的构造方法。若程序员自己定义了,则默认的构造方法就失效了。

3,方法重载

方法重载的规则就是相同的方法名可以有多个方法,但是必须保证参数不同,简称”同名不同参“。

public class ClassTest{
    public ClassTest{//构造方法
    }
    //方法重载
    public void test(int id){
    }
    public void test(String name){
    }
    public void test(double money){
    }
}

方法重载可以在不改变原来方法的基础上,新增功能。

4,变量和属性

类中可以有多个变量而变量可以有多个属性。

public class ClassTest{
     String mName;//不加修饰符的变量默认protected
     private int mId;//类中声明的变量

     public void setMyId(int id){//变量拥有的方法(属性)
     mId=id;
     }
     public int getMyId(){//变量拥有的方法(属性)
     return mId;
     }
}

其中,mName如果不添加修饰符,则java中默认protected。

5,封装

封装属于一种思想。一个类中声明一个方法,这个方法在传入规定的参数后就可以给你返回一个想要的结果。而方法中的各种逻辑和计算其他类不用管。

这种代码方式被称为”封装“。

public class ClassTest{

     public String checkMoneySize(double money) {
            if (money >= 100) {
                return "百元以上";
            } else if (money >= 1000) {
                return "千元以上";
            } else {
                return "";
            }
        }
}

那么,外部调用的话只需要调用方法,传入参数就可以得到相应的结果。

封装的优点:

1,减少耦合性

2,内部自由修改

3,清晰的传入参数和返回结果(对外的接口)

6,继承和重写(重构)

继承(extends)代表了一种”强耦合“的关系。

子类继承父类,拥有了父类的所有特性之外还可以拥有自己的特性。

子类还可以重写父类的所有非”private“的方法。

public class ClassTest {
        public String checkMoneySize(double money) {
            if (money >= 100) {
                return "百元以上";
            } else if (money >= 1000) {
                return "千元以上";
            } else {
                return "";
            }
        }
    }

    public class ClassTestTow extends ClassTest {
        @Override
        public String checkMoneySize(double money) {
            //return super.checkMoneySize(money);
            if (money >= 100) {
                return "百元以上";
            } else if (money >= 1000) {
                return "千元以上";
            } else if (money >= 10000) {
                return "万元以上";
            } else {
                return "";
            }
        }
    }

继承的关键字”extends “

重写父类方法的关键字是在重写父类方法后在其开始部位写上”@Override“

还有一种情况,就是需要保留父类方法的情况下重写。

那么就要加上”super.checkMoneySize(money);“

使用”super.”关键字+父类方法名。

这段代码放置位置也决定执行顺序,如果在重写方法里,super放在重写的方法之前,那么父类的方法则会优先执行,如果在子类所有重写代码之后加上super则子类的方法会优先执行。

继承的缺点在于”父类变,子类跟着变“,父类的实现细节暴露给了子类。

当两个类之间相似度很高的时候就可以考虑使用继承。

7,多态

多态是面向对象编程的三大特性之一。(封装,继承和多态)

多态特点在于子类以父类的身份去完成逻辑,用自己的逻辑去完成父类的目的。子类特有的属性不可以使用。

同时,为了使子类能够完全代替父类工作,常常使用”重写(@Override)“来表示父类的方法或者类。

//父类
    public class ClassTest {
        public String checkMoneySize(double money){
        //父类的方法取决于子类使用不使用
        if (money >= 10000)
                return "你的钱够10000了";
            else
                return "你的钱不够";
}
    }

    //实现其父类的具体类
    public class ClassTestOne extends ClassTest {
        //实现父方法
        @Override
        public String checkMoneySize(double money) {
            if (money >= 1000)
                return "你的钱够1000了";
            else
                return "你的钱不够";
        }
    }

    //实现其父类的具体类
    public class ClassTestTow extends ClassTest {
        //实现父方法
        @Override
        public String checkMoneySize(double money) {
            if (money >= 100)
                return "你的钱够100了";
            else
                return "你的钱不够";
        }
    }

    //测试方法
    public void test() {

        ClassTest classTestOne = new ClassTestTow();
        String a = classTestOne.checkMoneySize(1000);

        ClassTest classTestTow = new ClassTestOne();
        String b = classTestTow.checkMoneySize(100);
    }

通过代码可以看出,ClassTest 类他就有了两种状态,一个状态是ClassTestOne还有一个就是ClassTestTow.

不同的对象可以执行相同的动作,但是需要自己来实现。

多态的原理就是当父类方法被调用的时候,父类方法会被子类实现,去执行子类中的逻辑而非父类的。那么这个父类可以有多个子类,那么也就有了多种状态。

8,抽象类

抽象类不能实例化,因为它没有”意义“。

抽象类中的抽象方法必须被子类重写。

抽象方法没有具体的实现内容。

如果一个类中有抽象方法,那么这个类必须是抽象类。

抽象类存在的意义在于尽可能多的整合代码和逻辑,尽可能少的存放数据。

抽象类的存在就是为了被继承。所以,父类是抽象类的时候,子类可以是具体类也可以是抽象类但是末尾的子类必须是具体类要么这个抽象类的存在就没有意义。

//抽象类
    public abstract class ClassTest {
        public abstract String checkMoneySize(double money);
    }

    //实现其抽象类的具体类
    public class ClassTestOne extends ClassTest {
        //实现抽象方法
        @Override
        public String checkMoneySize(double money) {
            if (money >= 1000)
                return "你的钱够1000了";
            else
                return "你的钱不够";
        }
    }

    //实现其抽象类的具体类
    public class ClassTestTow extends ClassTest {
        //实现抽象方法
        @Override
        public String checkMoneySize(double money) {
            if (money >= 100)
                return "你的钱够100了";
            else
                return "你的钱不够";
        }
    }

    //测试方法
    public void test() {

        ClassTest classTestOne = new ClassTestTow();
        String a = classTestOne.checkMoneySize(1000);

        ClassTest classTestTow = new ClassTestOne();
        String b = classTestTow.checkMoneySize(100);
    }

ClassTestOne 和ClassTestTow 类都是具体类,都继承了抽象类ClassTest,并且重写了抽象方法。

ClassTest抽象类存在的意义就是ClassTestTow 和ClassTestOne都有一个判断金钱的方法checkMoneySize(double money)。

那么就可以实现一个抽象类来管理这个方法,而子类去实现。

9,接口

接口(interface)的目的就是为了把公共的方法和属性封装起来提供一个特定的接口,让外界去调用。

一个类如何实现了某个接口,那么这个接口下的所有方法都必须全部实现。

接口和抽象类比较相似,但是不同的是:

1,接口不能提供任何一个方法的执行方式

2,接口不能实例化不能有构造方法和变量也不能有修饰符(private等)。不能声抽象方法和静态方法。

一个类可以支持多个接口,多个类可以支持相同的接口。

接口的用法也不同,现在来看第一种

 //定义接口
    public interface ITest {
        String checkMoneySize(double money);
    }

    //实现其接口的具体类
    public class ClassTestThree implements ITest {
        //实现接口方法
        @Override
        public String checkMoneySize(double money) {
            if (money >= 100)
                return "你的钱够100了";
            else
                return "你的钱不够";
        }
    }
    //测试方法
    public void test() {
        ClassTestThree classTestThree=new ClassTestThree();
        String a=classTestThree.checkMoneySize(100);
        }

当一个类实现了某个接口,那么它就必须实现接口中的所有方法。

外部调用某个类(ClassTestThree )中的某个接口(ITest )的方法(checkMoneySize)的时候,类已经将接口方法做了逻辑处理。外部只需要传入参数和获得接口。

第二种接口使用方法:

//实现其接口的具体类
    public class ClassTestFour {
        private ITest iTest;
        private void checkMoneySize(ITest iTest) {
            this.iTest = iTest;
            try {
                Thread.sleep(2000);//睡2s,模拟耗时操作
                String a=iTest.checkMoneySize(100);//实现接口的时候,类传入处理的值
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //测试方法
    public void test() {
        ClassTestFour classTestFour=new ClassTestFour();
        classTestFour.checkMoneySize(new ITest() {
            @Override
            public String checkMoneySize(double money) {
            //调用类中的接口的方法的时候,获得类处理过的值 即获得money
                if (money >= 100)
                    return "你的钱够100了";
                else
                    return "你的钱不够";
            }
        });
    }

这种使用方式是类做一系列的逻辑处理,这个处理可能是耗时的 ,可能是异步的。

那么实现方法(test)在调用的时候就可以new这个类中的接口

当类处理完了接口返回的结果自然返回test类中的checkMoneySize方法的接口中,完成一次异步的调用。

接口的第二种用法就不为了异步的获得结果。

接口和抽象类是相反的生成原因。

抽象类是发现多个类有相同的逻辑代码,今儿生成抽象类。而接口是预先知道逻辑而定制的接口。

10,集合

java中的集合都继承于Collection

list集合中包含:Vector;LinkedList;ArrayList.

Set集合中包含:HashSet;LinkedHashSet;SortedSet;

Vector : 基于Array的List,其实就是封装了Array所不具备的一些功能方便我们使用,它受Array的限制。性能也就不可能超越Array。所以,在可能的情况下,我们要多运用Array。另外很重要的一点就是Vector 是线程同步的,这个也是Vector和ArrayList的唯一的区别。

ArrayList:同Vector一样是一个基于Array上的链表,但是不同的是ArrayList不是同步的。所以在性能上要比Vector优越一些,但是当运行到多线程环境中时,可需要自己在管理线程的同步问题。

不同线程同时添加arraylist就可能会出现位置冲突。

比较:所以,当你的list需要在多线程下添加删除的话,建议使用Vector;一般情况下使用arraylist;

LinkedList:LinkedList不同于前面两种List,它不是基于Array的,所以不受Array性能的限制。它每一个节点(Node)都包含两方面的内容:1.节点本身的数据(data);2.下一个节点的信息(nextNode)。所以当对LinkedList做添加,删除动作的时候就不用像基于Array的List一样,必须进行大量的数据移动。只要更改nextNode的相关信息就可以实现了。这就是LinkedList的优势。

比较:那么,LinkedList相对于Vector和ArrayList来说的优势就是不需要移动数据,所以,add和remove操作更加快捷。

但是,对于数据的读取和写入(get,set),LinkedList就不如前两种了。

List总结:

  1. 所有的List中只能容纳单个不同类型的对象组成的表,而不是Key-Value键值对。例如:[ tom,1,c ];
  2. 所有的List中可以有相同的元素,例如Vector中可以有 [ tom,koo,too,koo ];
  3. 所有的List中可以有null元素,例如[ tom,null,1 ];
  4. 基于Array的List(Vector,ArrayList)适合查询,而LinkedList(链表)适合添加,删除操作。

**HashSet:**List基本上都是以Array为基础。但是Set则是在HashMap的基础上来实现的。

**LinkedHashSet:**HashSet的一个子类,一个链表。

**TreeSet:**SortedSet的子类,它不同于HashSet的根本就是TreeSet是有序的。它是通过SortedMap来实现的。

可以看出set型集合中,HashSet和LinkedHashSet的差别在于基于HashMao的HashSet适合查询,而LinkedHashSet(链表)适合添加,删除操作。

而TreeSet和前两种不同在于它是有序的,适合查询而添加/删除较弱。

11,泛型

泛型的作用是作为参数的占位符。

例如List,其中,T就是泛型,就是arraylist的数据类型占位符。

当实例化一个arraylist的时候,我们可以这样做:

List list=new Arraylist<>();

其中的泛型就被具体参数类型所代替。

泛型的使用在设计android框架的时候运用广泛。

例如,listview的适配器adapter中需要优化,就必不可少的用到ViewHolder。

加入我们需要向这个ViewHolder中传入view以及数据。那么我们怎么做才能让这个ViewHolder能够适配所有类型的数据?

public class BaseAdapter<T extends ViewHolder>{
}

public class ViewHolder(){
    public ViewHolder(View root){
    }
}

那么当list集合每次调用程序中的BaseaAdapter时就能够给他传入一个数据类型

private class TestAdapter extends BaseAdapter<TestViewHolder>{
//BaseAdapter<T>中的泛型就被TestViewHolder

}

同样的我们再写一个不同的TestTowViewHolder也同样能够替换T这个泛型。

可能有人会问,代码中的泛型T extends ViewHolder是为什么?

这就是更加灵活的运用泛型的例子。

我们的适配器(BaseAdapter)只能传入ViewHolder,其他的类型不能接受。接收了适配器会解析不出来。

这个时候就有这么个需求,既要传进来的数据多样化,又要给这个多样化确定一个范围。那么就让这个T泛型 extends ViewHolder这个基类。

那么,泛型的作用就在于给一个集合体传入一个数据类型,而这个数据类型必不可少,也不能定死。这个时候就用泛型来充当占位符。

外界必须传入一种类型而内部也可以直接用占位符一直做逻辑处理

12,委托与事件

java的是没有委托的。但是事件在android中最好的体现就是各种监听事件。比如:点击事件监听,checkedchange监听。

委托是对函数的封装。可以理解为当前方法特征指定给一个名称,而事件就是委托的一种特殊形式。当发生事件的时候,事件就会处理通知过程。

我们来模仿一个android的点击事件:

//仿android点击事件
    public abstract class OnClickListener {
        private View v;

        public abstract void onClickListener(View v);

        private OnClickListener(View v) {
            this.v = v;
            if ("这里是view点击处理的逻辑代码".equals("用户点击的响应")) {
                onClickListener(v);
            }
        }
    }

    //测试
    private void test() {
        View v=findviewByid(R.id.test);
        new OnClickListener(v) {
            @Override
            public void onClickListener(View v) {
                //用户点击了该view就会把事件传递到这里

            }
        };
    }

这就相当于我们写一个点击事件,并声明一个view,将这个点击事件赋予view。当view做点击操作的时候,这个点击事件就会被触发。

总结

java或者android中面对对象编程的基础知识就包括这15点。当然还有更多知识点。

其中,三大思想是”封装,继承,多态“;

只有完全了解和运用了面对对象的基础,才能更好的去理解设计模式。

面对对象编程是更好理解设计模式的前提。

无前者不后者

时间: 2024-10-24 17:08:04

Android 内功心法(番外)——写在设计模式前,面对对象编程基础的相关文章

编程珠玑番外篇

1.Plan 9 的八卦 在 Windows 下喜欢用 FTP 的同学抱怨 Linux 下面没有如 LeapFTP 那样的方便的工具. 在苹果下面用惯了 Cyberduck 的同学可能也会抱怨 Linux 下面使用 FTP 和 SFTP 是一件麻烦的事情. 其实一点都不麻烦, 因为在 LINUX 系统上压根就不需要用 FTP. 为什么呢? 因为一行简单的配置之后, 你就可以像使用本机文件一样使用远程的任何文件. 无论是想编辑, 查看还是删除重命名, 都和本机文件一样的用. 这么神奇的功能到底如何

【喵&quot;的Android之路】【番外篇】关于==和equals

[喵"的Android之路][番外篇]关于==和equals 在实际的编程当中,经常会使用==和equals来判断变量是否相同.但是这两种比较方式也常常让人搞得云里雾里摸不着头脑.下面是我个人做的总结,希望能起到拨云见日的作用. [讲前普及] 请阅读 [喵"的Android之路][基础篇(一)][Java面向对象基础]数据类型与运算符 了解Java基本数据类型和引用数据类型 1."=="运算符 通俗点讲,==运算符比较的是两个变量在栈中的内容是否相同. 以a ==

Monkey源码分析番外篇之Android注入事件的三种方法比较

原文:http://www.pocketmagic.net/2012/04/injecting-events-programatically-on-android/#.VEoIoIuUcaV 往下分析monkey事件注入源码之前先了解下在android系统下事件注入的方式,翻译一篇国外文章如下. Method 1: Using internal APIs 方法1:使用内部APIs This approach has its risks, like it is always with intern

Android好奇宝宝_番外篇_看脸的世界_05

上一篇番外篇讲了一个炒鸡炒鸡简单的自定义ProgressBar,这一篇基于上一篇的基础扩展为SeekBar,没看过上一篇的,请先看一遍:传送门 先上效果图(2G内存的机子运行模拟器,所以有点卡): 这个效果之前不知道在哪里看到过,我也忘了. 下面进入正题: 测量大小和绘制部分沿用上一篇ProgressBar的,不清楚的请走上面的传送门. 对比上一篇的扩展: (1)SeekBar能通过触摸改变刻度 (2)SeekBar上方添加一个显示当前刻度的浮动View(后面用FloatView表示) (1)通

【喵&quot;的Android之路】【番外篇】有关于null的一些知识点

[喵"的Android之路][番外篇]有关于null的一些知识点 1.首先,到底什么是null? null是Java中的一个关键字,用于表示一个空对象引用,但其本身并不是任何类型也不是属于任何对象.因此,下面的做法是错误的: int a = null; 但: Object obj = null; 是可以的,因为null表示Object类型的一个空对象引用,符合其用意. [注1]引用类型使用null声明对象变量后,无法使用该变量访问对象的成员.例如上述obj对象如果使用obj.toString()

iOS冰与火之歌番外篇 - 在非越狱手机上进行App Hook(转载)

作者简介:郑旻(花名蒸米),阿里巴巴移动安全部门资深安全工程师,香港中文大学移动安全(Android & iOS)方向博士,曾在腾讯.百度以及硅谷的FireEye实习.在博士期间发表了多篇移动安全方向的论文(BlackHat.AsiaCCS等),去过10多个不同的国家做论文演讲. 曾帮助Apple公司修复了多处iOS安全问题,并且Apple在官网表示感谢.同时也是蓝莲花战队和Insight-labs的成员,在业余时间多次参加信息安全竞赛(Defcon.AliCTF.GeekPwn等),并取得优异

Linux入门之内核管理番外篇(4)udev入门(1)

Linux入门之内核管理番外篇(4)udev入门(1) 前言 在上篇中的内核模块管理讲解中,最后或多或少会留下一些疑问,那么这些疑问就是内核模块的参数是怎么和对应的硬件所匹配上的,而硬件又是怎么被内核识别,并且一个个都映射成实际存在的文件,而这些文件之间的关系及作用.当然在最后了解到,这些硬件设备的探测信息是通过一个叫udev的工具来实现的,通过udev中配置的规则可以很有效的识别每一个硬件,并配合sysfs文件系统,将每个探测到的硬件信息导入到/sys目录中,那么与/proc目录对与内核系统信

【转载】数学之美番外篇:平凡而又神奇的贝叶斯方法

数学之美番外篇:平凡而又神奇的贝叶斯方法 BY 刘未鹏 – SEPTEMBER 21, 2008POSTED IN: 数学, 机器学习与人工智能, 计算机科学 概率论只不过是把常识用数学公式表达了出来. ——拉普拉斯 记得读本科的时候,最喜欢到城里的计算机书店里面去闲逛,一逛就是好几个小时:有一次,在书店看到一本书,名叫贝叶斯方法.当时数学系的课程还没有学到概率统计.我心想,一个方法能够专门写出一本书来,肯定很牛逼.后来,我发现当初的那个朴素归纳推理成立了——这果然是个牛逼的方法. ——题记 目

编程珠玑番外篇之番外篇-O 中间语言和虚拟机漫谈(ZZ)

http://blog.youxu.info/2014/05/11/language-and-vm/ 导言 编程语言的发展历史,总的来说,是一个从抽象机器操作逐步进化为抽象人的思维的过程.机器操作和人的思维如一枚硬币的两面,而语言编译器就像是个双面胶,将这两面粘在一起,保证编程语言源程序和机器代码在行为上等价.当然,人本身并不是一个完美的编译器,不能无错的将思维表达为高级语言程序,这种偏差,即Bug.因为编译器的帮助,我们可以脱离机器细节,只关心表达思维和程序行为这一面. 编程语言的发展日新月异