杂记
封装:对象,容器都是封装;封装的目的是高内聚低耦合。
头文件中初始化和构造函数中初始化的区别?
在头文件中初始化就相当于该实例/变量是一直存在的,会导致性能浪费。
在构造函数中初始化则是用的时候再创建,符合面向变化和节约性能的需求。
不要在创建属性时直接实例化,例如:
public class Game
{
...
private IUserinfoSerice us = new IUserinfoSerice();
//wrong! 因为IUserinfoSerice作为接口时,后面实例化的可能是派生类,而不是IUserinfoSerice,如下面初始化为UserinfoSerice1()
//此时相当于把项目权限写死了,后期面临变化时会很崩溃。因此在构造函数中来初始化属性。
private IUserinfoSerice us;
public Game()
{
us=UserinfoSerice1(); //Right!
}
...
}
值类型和引用类型的区别:
值类型传递时传递的是数值,引用类型传递时传递的是地址。
内存和硬盘的区别:
硬盘的数据是不能被删除的,只能被复写,当使用删除时,通过一定手段是可以恢复的,但复写后就不能被恢复了。
内存和硬盘差不多,只要内存存在,数据就一直存在。但是内存与硬盘不同的地方是,内存只有上电的时候才会被开辟,才会工作。
因此,只要new之后的内存只要没有被回收,就一直存在。
继承的目的:重用和改写,即覆写。
当你不想重用和改写时,只是用原来的方法,那么继承没有意义,直接包含就可以了。
那么如何来改写?
在java中使用@override
来辅助检查重写方法,super(父类),this(自己)。
super的用法?
当覆写父类方法后,默认调用的是覆写后的方法,当不想用覆写的方法,只想用原来的方法,就需要使用super.method()来调用父类方法。
举个例子,手机都有拍照功能,小米和华为。。。。
java只能单继承,不能多重继承。当需要多重继承时,可以使用传递继承代替。
使用子类构造函数的时候,必须先使用super实例化父类构造函数。
java包,就是文件夹的概念。
包的命名方式。
1.com或org,com(公司),org(组织),组织就是各方势力融合;
2.公司名;
3.项目名;
4.模块名。
导入包:import
- java.lang java语言包,任何程序中,该包都会被自动导入;
- java.awt 图形用户界面包;
- java.awt.event 图形用户界面事件处理包;
- java.swing 跨平台轻量级组件包;
- java.sql 数据库访问包;
- java.io 输入输出
- java.util 该包提供了许多工具如:lists,calendar,date等所需要的类和接口;
- java.net TCP/IP网络编程,逐渐被websocket所代替。
封装是为了加权限,访问权限其实就是锁。
java访问权限
访问权限 | 本类 | 本包的类 | 子类 | 非子类的外包类 |
---|---|---|---|---|
public | 是 | 是 | 是 | 是 |
protected | 是 | 是 | 是 | 否 |
default | 是 | 是 | 否 | 否 |
private | 是 | 否 | 否 | 否 |
什么都不写时是default访问权限。
方法覆写时权限不能小于父类中方法的权限,否则无法调用父类方法。
引用数据类型的转换
向上转换--子类转换为父类,损失了子类新扩展的属性和方法,仅可以使用从父类中继承的属性和方法。
向下转换--父类转换为子类,曾经向上转换过的对象,才能向下转换,。对象不允许不经过向上转换而直接向下转换。
使用instanceof运算符来判断向上转换后的对象是哪一个子类。
当我要改写项目中一个业务的时候,不要盲目直接否定改写该业务,而是新建一个重写。当实现一个方法时,客户觉得不好,但是不要去改这个方法,而是继承原来的方法重新实现该方法,因为即使客户不喜欢,但是也许客户的领导喜欢,因此不是改写而是继承。
接口只提供虚方法,可以多重继承,是架构师来实现的,他关注的是程序有什么;实现是我们来做的,我们关注的是怎么去实现。
final关键字:
final修饰的
- 类:不能被继承;
- 变量:不能被重新赋值;在声明时赋值,或在构造函数中赋值;系统不会对final属性默认的赋初始值。
- 方法:不能在子类中被覆盖,即不能被修改。
1.final空白
public final int a;//final空白
//这种情况下,就必须在构造函数中用参数列表初始化。
2.final参数
final参数不能被改变。
public class Test{
public method(final int i)
{
i++;//
}
}
在程序中经常使用的一些常量,如圆周率,没必要在程序中频繁的修改它,那么我们可以:
- 首先把他设置为静态static,多个实例共享该常量,没有必要每个对象保存一份;
- 其次,设置为final类型,赋值以后不你们再改变;
- 最后注意遵守常量的命名会犯,所有字母大写,单词之间用下划线。
多态的第一步,抽象类。
有抽象方法的一定是抽象类。
抽象类的规则:
- 抽象类不能被实例化;
- 其包含的抽象方法必须在其子类中被实现,否则该子类只能声明为abstract;
- 抽象方法不能为static。
在下列情况下,一个类必须声明为抽象类:
- 当一个类的一个或多个方法是抽象方法时;
- 当类是一个抽象类的子类,并且没有实现父类的所有抽象方法,即只实现部分;
- 当换一个类实现一个接口,并且不能为全部抽象方法都提供实现时;
接口(interface)
- 接口中的所有方法均为抽象方法(不用写关键字);
- 接口中只包含常量和抽象方法,而没有变量和方法的实现;
- 接口使用关键字interface来创建;
- 子类必须实现接口的所有方法,除非是抽象类。
- 接口中的方法必须是public。
- 在接口中默认就是public,而不是default。
- 接口不能有非抽象方法,但抽象类可以有非抽象方法。
- 接口也可以继承接口。
工厂模式与抽象类。
工厂模式有简单工厂模式,工厂方法模式和抽象工厂模式。
public class SendFactory{
//简单工厂模式,传递的是字符串
public static Sender produce1(String type){
Sender s=null;
if("wechat".equals(type)){
s=new WechatSender();
}else if("sms".equals(type)){
s=new SmsSender();
}
return s;
}
//工厂方法模式,直接调用构造方法,工厂可以有很多个产品,产品是抽象的。
public static Sender ProduceWechat(){
return new WechatSender();
}
public static Sender ProduceSms(){
return new SmsSender();
}
}
//以下是抽象工厂模式。抽象工厂模式是在简单工厂模式和工厂方法模式之上再次抽象了工厂类,将工厂类统一化了。
//如上边的是SendFactory工厂类,以后还可能有FruitFactory工厂类,因此这些工厂类可以统一化为Provider抽象类。
//抽象为抽象工厂类的目的是为了扩展,在不修改原来代码的情况下还能新增功能。
//工厂接口
public interface Provider{
public Sender Produce();
}
//现在一个工厂和一个产品对应了。
public class WechatFactory implements Provider{
@override
public Sender Produce(){
return new WechatSender();
}
}
//使用方法如下:
Provider factory=new WechatFactory(); //当我不需要这个工厂时,只需要换一个工厂即可,其他都不需要改变。
Sender sender=factory.produce();
sender.send();
使用接口这种方式,可以通过继承来实现升级,避免了抛弃旧版本的内容。
多态
多态:就是将做什么和怎么做分离;分别对应了接口和实现的分离来完成;通过多态来消除类型之间的耦合关系;多态也叫动态绑定。
批注:这个定义蛮好的,分别解释了什么是?怎么做?为什么?多态举例,如计算机的视频接口可以接很多类型的显示器。
多态的三个条件:
- 要有继承或者实现;
- 要有重写;
- 父类引用指向子类对象。(子类的对象赋予父类对象的引用)
static关键字
static可修饰的元素:
- 属性
- 方法
- 代码块
- 不能修饰局部变量
static特点:
- 静态的,全局的
- 被static修饰的成员变量和成员方法独立于该类的任何对象。不依赖于特定的实例,被类共享。只要这个类被加载(注意不是对象被加载),java的JVM就能根据类名在运行时数据区的方法内找到他们。
- 由于被static修饰的方法或变量只存在一个,那么就衍生了一个特殊的使用,单例模式。
静态方法的作用:
- 简化方法的使用;
- 便于访问静态属性;
注意事项:
- 静态方法里只能直接访问静态成员,而不能直接访问类中的非静态成员。
- 静态方法中不能使用this,super关键字。
- 静态方法不能被非静态方法覆盖,静态方法不能修饰构造器。
静态代码块:
- 一个类中由static关键字修饰的,不包含在任何方法体中的代码块;
- 当类被载入时,静态代码块被执行,且只被执行一次;
- 静态块经常用来进行类属性的初始化。
单例模式
单例模式(singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点。
public class Singleton{
//私有静态实例,仿制被直接引用。
//赋值null,目的就是实现延迟加载。不是引用类时就创建实例,而是在调用实例时再创建实例。
private static Singleton instance=null;
private Singleton(){
}
public static Singleton getInstance(){
if(instance==null)
{
instance=new Singleton();
}
return instance;
}
public Object readResolve(){
return instance;
}
}
当在多线程中使用的都应该是同一个对象。不管这个对象在哪使用,这个对象都应该是唯一的。
单例模式使用情况举例:
- 任务管理器。
- Spring ioc Bean默认都是单例的。
单例模式要点:
- 某个类只能有一个实例;
- 他必须自行创建这个实例;
- 必须自行向整个系统提供这个实例。
内部类
内部类:定义在一个类中的另一个类,也叫嵌套类。
外部类:包含内部类的类。
作用:
- 提供了更好的封装,可以把内部类隐藏在外部类之内。
- 内部类的成员可以直接访问外部类的私有成员。
- 匿名内部类适合用于创建仅需要一次使用的类。
普通类的访问权限修饰符
- default
- public
内部类的访问权限修饰符
- default
- public
- protected
- private
静态内部类
使用static来修饰的内部类,这个内部类不属于任何类的对象,只属于类的本身。
静态内部类无法访问外部类的实例。
批注:静态成员其实就是作用域内共享的一块内存,作用域可以使类/函数/文件。静态成员和全局变量一起被存放在静态区,在程序运行时就被实例化,同时将没初始化的值初始化为0。
局部内部类
定义:把一个内部类放在方法里定义。局部内部类仅在方法里有效,不能使用访问修饰符和static来修饰。
匿名内部类
概念:适合创建只需要一次使用的类,创建匿名内部类时会立即创建一个该类的实例,这个定义立即消失。
使用时可以直接使用new来创建一个匿名类。
枚举类
批注:静态常量(static final)和枚举量(enum)可以通用,但是枚举量可以索引就更好用了。
常量模式:很多程序员和企业都喜欢定义静态常量,并把这些常量放在一个常量类中,看起来很规矩。
枚举解决了静态常量类型不安全的问题。
- 静态常量可以做四则运算,枚举不允许;
- 静态常量没有命名空间,这些常量随便用。
枚举模式:
使用enum关键字来定义枚举类。
- 可以实现一个或多个接口;
- 不能有子类;
- 只能使用private来做构造器;
- 枚举类的所有实例必须在类的第一个行显示列出。
//定义,枚举是个类。
public enum GoodState{
ON,DOWN,REMOVE;
}
//使用
GoodState g=GoodState.valueOf("ON");
if(GoodState.ON==g)
...
反射
概念:反射是指在运行时
状态可以知道任意一个类的所有属性和方法,对任意一个对象都可以调用他的任意一个方法;通过反射,可以在运行时实例化对象;
跟反射直接相关的模式就是代理模式。
通过反射可以:
- 在运行时判断一个对象所属的类;
- 在运行时构造任意一个类的对象。
- 在运行时判断任意一个类的成员变量和方法;
- 在运行时任意一个对象的方法;
- 生成动态代理。
示例
1.获取一个对象的包名或类名。
package com.xxx.demo;
public class Test{
public static void main(Stringp[] args){
Test trf=new Test();
System.out.println(trf.getClass().getName());
}
}
com.xxx.demo.Test
2.实例化class类的对象
package com.xxx.demo;
import java.lang.reflect.Method;
public class Test{
public void info(){
System.out.println("ok!");
}
public static void main(Stringp[] args){
// ? 是通配符,可以指向任何类型。class1作为中间类来使用。
Class<?> class1=null;
//将class1赋值为com.xxx.demo.Test类型。
class1=Class.forName("com.xxx.demo.Test");
//实例化对象
Test test=(Test)class1.newInstance();
test.info();
//获取方法
Method method[]=class1.getMethods();
for(ing i=0;i<method.length;i++){
System.out.println(method[i].getName());
}
}
}
ok!
什么是java运行时环境?就是java运行的时候计算机给你提供了什么。
Object
Object是所有类的基础。
Object提供了以下方法:
//比较两个对象是否是同一个对象(比较哈希地址)
public boolean equals(Object obj)
//返回对象的哈希码。
public int hashCode()
//返回对象的字符串。
public String toString()
equals()与的区别?
默认情况下(equals没有被重写),equals只能比较引用类型;既能比较引用类型也能比较基本类型。
包装类
java语言不把基本数据类型看做对象,因为它存在与栈中,不存在与堆中。
因此java提供了包装类将基本数据类型转化为对象。
批注:包装应该和适配器是一个意思,将一个转换为另一个。
int pInt=500;
Integer wInt = new Integer(pInt);
接口可以被赋值为子类但不能new
实现类和实例化:实现类是接口的实现类,因为接口不能new,而实现类能new;类是一种自定义类型,不能直接用,就像不能直接用int一样,所以需要实例化类,即创建一个对象。
三种存储方式:顺序存储,链式存储,以及映射存储。
java集合
集合:保存不定量的数据和映射关系的数据。
在java.util包中含有集合的接口。
equals()和 ==
在没有被重写的情况下,equals()是深比较,是浅比较。
举个通俗的例子来说,是判断两个人是不是住在同一个地址,而equals是判断同一个地址里住的人是不是同一个。
Collection接口
可以放置不同类型的元素。
Set接口
Set:无序集合,不允许重复。
如果e1.equals(e2)为ture,则认为e1和e2重复。
两个实例类子类:
HashSet,哈希存储且无序存储; LinkedHashSet,链式存储并哈希(插入和删除快一点)。
TreeSet,有序集合,它的作用是提供有序的Set集合。
List接口
List:有序集合,允许重复。
两个实现类子类:
ArrayList:顺序存储,动态数组。
LinkedList: LinkedList类是双向列表,列表中的每个节点都包含了对前一个和后一个元素的引用。