Java入门级概述
Posted 哪 吒
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java入门级概述相关的知识,希望对你有一定的参考价值。
🍅 Java学习路线:搬砖工逆袭Java架构师
🍅 简介:Java领域优质创作者🏆、CSDN哪吒公众号作者✌ 、Java架构师奋斗者
🍅 扫描主页左侧二维码,加入群聊,一起学习、一起进步
🍅 欢迎点赞 👍 收藏 ⭐留言 📝
一、语言的五大特性
1、万物皆对象
2、程序就是多个对象彼此调用方法的过程
3、从内存角度而言,每个对象都是由其它更基础的对象组成的
4、每一个对象都有类型,都可以进行实例化
5、同一类型的对象可以接收相同的消息
面向对象编程的最大挑战就是如何在问题空间的元素和解决方案空间的对象之间建立一对一的关联。
二、类
类的创建者负责在创建新的类时,只暴露必要的接口给客户程序员,同时隐藏其它所有不必要的信息。
为什么这么做呢?
1、因为如果这些信息对于客户程序员而言是不可见的,那么类的创建者就可以任意修改隐藏信息,而无需担心对其它任何人造成影响。隐藏的代码通常代表着一个对象内部脆弱的部分,如果轻易暴露给粗心或经验不足的客户程序员,就可能在顷刻之间被破坏殆尽。所以,隐藏代码的具体实现可以有效减少程序bug。
2、让类库的设计者在改变类的内部工作机制时,不用担心影响到使用该类的客户程序员。
Java提供了三个显示关键字来控制访问权限
修饰词 | 本类 | 同一个包的类 | 继承类 | 其他类 |
---|---|---|---|---|
private | √ | × | × | × |
无(默认) | √ | √ | × | × |
protected | √ | √ | √ | × |
public | √ | √ | √ | √ |
三、对象间的四种关系
1、依赖
依赖关系表示一个类依赖于另一个类的定义。例如,一个人(Person)可以买车(car)和房子(House),Person类依赖于Car类和House类的定义,因为Person类引用了Car和House。与关联不同的是,Person类里并没有Car和House类型的属性,Car和House的实例是以参量的方式传入到buy()方法中去的。一般而言,依赖关系在Java语言中体现为局域变量、方法的形参,或者对静态方法的调用。
2、关联
关联(Association)关系是类与类之间的联接,它使一个类知道另一个类的属性和方法。关联可以是双向的,也可以是单向的。在Java语言中,关联关系一般使用成员变量来实现。
3、聚合
聚合(Aggregation) 关系是关联关系的一种,是强的关联关系。聚合是整体和个体之间的关系。例如,汽车类与引擎类、轮胎类,以及其它的零件类之间的关系便整体和个体的关系。与关联关系一样,聚合关系也是通过实例变量实现的。但是关联关系所涉及的两个类是处在同一层次上的,而在聚合关系中,两个类是处在不平等层次上的,一个代表整体,另一个代表部分。
4、组合
组合(Composition) 关系是关联关系的一种,是比聚合关系强的关系。它要求普通的聚合关系中代表整体的对象负责代表部分对象的生命周期,组合关系是不能共享的。代表整体的对象需要负责保持部分对象和存活,在一些情况下将负责代表部分的对象湮灭掉。代表整体的对象可以将代表部分的对象传递给另一个对象,由后者负责此对象的生命周期。换言之,代表部分的对象在每一个时刻只能与一个对象发生组合关系,由后者排他地负责生命周期。部分和整体的生命周期一样。
三、封装、继承、多态
1、封装
封装就是把对象的属性和行为结合为一个独立的整体,并尽可能多的隐藏对象的内部实现细节。
2、继承
对象用来封装数据和功能,但我们要创建一个新类,然而它又与已存在的类具有部分相同的属性或功能,此时,为了代码复用原则,可以使用继承来实现。
继承通过基类和子类的概念来表达,基类的所有特征和行为都可以与子类共享。也就是说,你可以通过基类呈现核心思想,从基类继承的子类则为核心思想提供不同的实现方式。
有时基类和子类的方法都是一样的,这时你就可以直接用子类的对象代替基类的对象,这种纯替代关系通常叫做替换原则。
有时,子类会添加一些新的方法,此时就是不完美替换。
3、多态
通过将子类对象引用赋给父类对象引用来实现动态方法调用。
List<String> list = new ArrayList<String>();
四、单根层次结构
Java就是一个很明显的单根层次结构的语言,所有的类都继承自Object类。
单根层次结构有利于实现垃圾回收期,这也是Java对比C++的一个重要改进。
异常也是一样的,异常的根类是Throwable,Throwable的直接子类是Exception和Error。
五、集合
通常情况下解决一个问题可能需要多个对象,也无法确切的知道要申请多大的内存空间,这时我们可以建一个新的对象,囊括你所需要的一切,这个新对象就称为集合。
Java中最重要的集合有list、map、set、queue、tree、stack等。
常用集合的分类:
Collection 接口的接口 对象的集合(单列集合)
├——-List 接口:元素按进入先后有序保存,可重复
│—————-├ LinkedList 接口实现类, 链表, 插入删除, 没有同步, 线程不安全
│—————-├ ArrayList 接口实现类, 数组, 随机访问, 没有同步, 线程不安全
│—————-└ Vector 接口实现类 数组, 同步, 线程安全
│ ———————-└ Stack 是Vector类的实现类
└——-Set 接口: 仅接收一次,不可重复,并做内部排序
├—————-└HashSet 使用hash表(数组)存储元素
│————————└ LinkedHashSet 链表维护元素的插入次序
└ —————-TreeSet 底层实现为二叉树,元素排好序
Map 接口 键值对的集合 (双列集合)
├———Hashtable 接口实现类, 同步, 线程安全
├———HashMap 接口实现类 ,没有同步, 线程不安全-
│—————–├ LinkedHashMap 双向链表和哈希表实现
│—————–└ WeakHashMap
├ ——–TreeMap 红黑树对所有的key进行排序
└———IdentifyHashMap
六、泛型
在Java5之前,JAVA语言的集合所支持的通用类型是Object。因为单根结构决定了所有对象都属于Object类型,所以一个持有Object的集合就可以持有任何对象,这就使得集合十分易于复用。
其实并不能保存原始数据类型,不过自动装箱机制在一定程度上解决了这个问题。
当集合中持有Object类型时,要添加一个对象到集合中,该对象会向上转型为Object,从而失去了原本的类型。当你需要将其取出时,会获得一个Object类型的对象引用,这就不是当初的类型了,需要进行向下转型。但除非明确知道对象的具体类型,否则向下转型是不安全的,转型失败会抛出异常。
这个问题的解决方式是“参数化类型”,一个被参数化的类型是一种特殊的类,可以让编译器自动适配特定的类型,参数化类型也叫泛型,通过尖括号中间加上类名来定义泛型,比如List<String>。
七、对象的创建和声明周期
对象的创建需要消耗一些资源,尤其是内存资源。
当我们不再需要一个对象时,就要及时清理它,这样占用的资源才能被释放并重复使用。
如果要最大化运行时效率,可以通过栈区(局部变量)来保存对象,或者将对象保存在静态区里,这样在编写程序时就可以明确的知道对象的内存分配和生命周期,这种做法会优先考虑分配和释放内存的速度。但是代价就是牺牲了灵活性,因为你必须在编写代码时就明确对象的数量、生命周期以及类型,但是这种写法的限制性很大。
还有一种方案是在内存池中动态创建对象,这个内存池也就堆。如果使用这个方案,直到运行时你才能知道需要多少对象,以及它们的生命周期和确切的类型是什么。如果需要创建一个新对象,可以直接通过堆来创建。因为堆是在运行时动态管理内存的,所以堆分配内存所花费的时间通常会比栈多一些。栈通常利用汇编指令向下或向上移动栈指针来管理内存,而堆何时分配内存则取决于内存机制的实现方式。
Java只允许动态分配内存,每当要创建一个对象时,都需要使用new来创建一个对象的动态实例。
如果在栈中创建对象,编译器会判断对象存在时间以及负责自动销毁该对象。
如果在堆中创建对象,编译器就无法得知对象的生命周期。
Java支持垃圾回收机制,它会自动找到没用的对象将其销毁。
八、异常处理
异常处理是将编程语言和错误处理机制直接绑定在一起,异常从错误发生处抛出,根据错误类型,可以对其进行捕获。由于异常的存在,降低了编写代码的成本,不用经常反复检查各种错误。
如果抛出异常,就确保了它会被有效的处理,这也增强了程序的健壮性。
Java的异常处理机制在众多编程语言中几乎可以说是鹤立鸡群的,异常时Java唯一允许的报错方式,如果你的代码没有正确的处理异常,就会得到一条编译时的报错消息。
❤️详解Java异常❤️代码报错怎么办,try catch盖住不就好了?
九、数据保存在哪里
1、寄存器
寄存器是速度最快的数据存储方式,数据直接保存在中央处理器,然而寄存器的数量是有限的,所以只能按需分配。
JVM中有4种常见的寄存器:
- pc程序寄存器
- optop操作数栈顶指针
- frame当前执行环境指针
- vars指向当前执行环境中第一个局部变量的指针
所有寄存器都为32位。
pc用于记录程序的执行,optop,frame和vars用于记录指向Java栈区的指针。
2、栈
数据存储在随机存取存储器里,处理器可以通过栈指针直接操作该数据。具体来说,栈指针向下移动将申请一块新的内存,向上移动则会释放这块内存。这是一种及其迅速和高效的内存分配方式,其效率仅次于寄存器。只不过Java系统在创建应用程序时就必须明确栈上所有对象的生命周期。这种限制约束了程序的灵活性,因此虽然有一些数据会保存在栈上,对象本身却并非如此。
3、堆
堆是一个通用的内存池,用于存放所有Java对象,new出来的对象都存放在堆中。堆内存的分配和清理要比栈存储话费更多的时间。
4、常量存储
常量通常会直接写在程序代码中,不可变。
5、非RAM存储
不保存在应用程序里的数据,最典型的例子就是序列化对象,它指的是转换为字节流并可以发送到其它机器的对象。另一个例子则是持久化对象,它指的是保存在磁盘上的对象。也支持使用数据库存储对象信息。
大多数微处理芯片有额外的缓存内存,只不过缓存内容使用的是传统的内存管理方式,而非寄存器。
一个例子是字符串常量池,所有字符串和字符串常量都会被自动放置到这个特殊的存储空间中。
特殊情况 -> 原始类型
原始类型是直接创建一个“自动变量”,不是引用,该变量直接在栈上保存它的值,运行效率更高。
十、Java中的一些常见概念
1、数组
Java的数组一定会被初始化,并且无法访问数组边界之外的元素,这种边界检查的代价是需要消耗少许内存,以及运行时需要少量时间来验证索引的正确性。当创建一个放置对象的数组时,实际上数组里包含的是引用,这些引用都有一个特殊的值null,Java会认为null的引用没有指向任何对象,所以当你操作引用之前,需要确保将其指向了某个对象。如果你试图操作一个值为null的引用,系统会返回一个运行时错误。
2、移位操作符
移位操作符也操纵二进制位,它们只能用来处理基本类型里的整数类型。左移位操作符(<<
)会将操作符左侧的操作数向左移动,移动的位数在操作符右侧指定(低位补0)。“有符号”的右移位操作符(>>
)则按照操作符右侧指定的位数将操作符左侧的操作数向右移动。“有符号”的右移位操作符使用了“符号扩展”:如果符号为正,则在高位插入0,否则在高位插入1。
3、按位操作符
按位操作符用来操作整数基本数据类型中的单个二进制位(bit
)。按位操作符会对两个参数中对应的二进制位执行布尔代数运算,并生成一个结果。
4、三元运算符
相当于ifelse。
🔥联系作者,或者扫描作者主页二维码加群,加入我们吧🔥
推荐阅读
Java学习路线总结❤️搬砖工逆袭Java架构师❤️(全网最强,建议收藏)
以上是关于Java入门级概述的主要内容,如果未能解决你的问题,请参考以下文章
Cg入门19:Fragment shader - 片段级模型动态变色
Cg入门16:Fragment shader - 片段级光照