面向对象 Object Oriented
面试常考点:面向对象的特性?
面向对象是一个建模的思路,关注具备功能(函数方法)的对象,把有共同属性和功能的对象视为一个类,将这些共同的属性和功能/行为抽象出来,并且封装进类class
里实现。如果后面需要做一些工作(需求)的时候,就创建对象(new),让对象来做这些事情(调用方法)。这就很像一个工具。
对象是很厉害的,封装了一堆你想要实现的功能。你不需要知道这些功能怎么实现,只要创建对象并且调对象的对应的方法就行。
(spring中的控制反转就是将创建对象的这个控制权限也交给spring了,只需要提供配置文件就可以让spring的容器生成Bean对象。工厂模式)
还可能考到的:c++和java的区别?这里面向过程/面向对象也是一个区别,还可以答指针,内存回收等。
面向过程需要关注很繁琐的过程。而面向对象不用关注实现的具体细节,而是关注统筹架构(宏观整体)的问题。
面向对象常考面试题-三大特征
- 封装:所有内容对外部不可见(外部只能调方法)
- 继承:将其他的功能继承并发展
- 多态:方法的重载本身就是多态性的体现 (相同方法名,不同参数)
还有可能问到的扩展问题:多态在类加载的哪个阶段?
类与对象
类是共性,是总结起来的总和特征,对象是个性,是个体。
根据类制造对象。类里面有抽象出来的共同属性和方法,定义对象的操作。类必须通过对象才可以使用。
类的定义
public class Demo{
//成员属性
//成员方法
}
一个.java文件里可以存在N个类,但只能存在一个public修饰的类。这表示编译单元有单一的公共接口。.java的名称必须与public修饰的类完全一致。(但是内部类可以有public)
内存区域
栈
答题要点:
- 可访问特性:栈中元素线程私有,其他栈不可访问。
- 数据结构特性:先进先出。
- 存取速度:比堆快,仅次于PC寄存器
- (存取快的原因)栈内存空间的创建与释放:栈指针的移动->确定大小和范围->对数据存储出现限制->只存储少部分数据(大部分数据存储于堆内存中)
- 数据存储的限制:数据大小与生存期都已确定(如何确定?),缺乏灵活性。
- 存储内容:基本数据类型的数据+引用数据类型的引用
堆
- 存储内容:类的对象(通过new创建的那些,new是告诉JVM去开辟新的一块堆内存空间去创建新的对象)
- 存储空间:创建的时候不用管
- 内存释放:当不存在该对象的引用时,视为垃圾,垃圾回收器回收。
方法区
创建对象时,类的信息+方法就被加载到了方法区里。
内存创建过程
- Book b1 存入栈内存,赋值null
- = new Book();放入堆内存,得到内存地址比如0x1234,则占内存中修改b1的null为引用(0x1234)。
- 先从栈内存找b1,得到内存地址(引用)0x1234,然后到堆内存的相应位置上找对象。
- 复制对象,添加b2进栈内存,在栈内存中是相同的引用。
- 释放:先从栈内存以后进先出的形式释放,这样堆内存中的对象就没有引用,就会被GC。
方法重载
如果一个方法只是定义来运算int类型的,但是此时需要运算double?
类中定义的方法允许重载(相同的方法名称),限制有:
- 方法名称相同
- 参数列表长度||类型||顺序
如果只是返回值不一样,不构成方法重载。
匿名
没有引用名。在栈内存中有名字,里面存储引用,指向堆内存。
如果是匿名对象,只能用一次,因为下一次就找不到堆内存的位置了。
直接创建对象并调用方法 new Math().sum();
封装
设置对象的时候会遇见逻辑错误,如果直接操作对象,不能避免。封装的意义就是保护或防止数据无意破坏。就是不让类以外的程序直接访问和修改成员属性。如何实现?
- 隐藏对象的属性和实现细节(将属性私有)
- 仅对外公开方法,并且还控制方法的访问级别
即,将成员属性修饰为private
这样别的程序就不能直接操作对象的属性啦。
在赋值时传入的参数不符合要求(if判断),打印错误。
this关键字
调属性调方法都行。
Person(){
this("xxx",1);//this调用了另一个构造方法
}
Person(String s, int a){
}
- this在一个构造方法中,调用另一个构造方法时,必须编写在第一行,构建完对象之后才能对对象进行操作。(super也有这个特性,原因?)
快捷创建getter和setter
- 放在声明的属性后面可以创建(source)
- shift+alt+s也可以
如果有很多员工需要修改同一属性至同一值region
- 让region指向一个static变量“北京”
原:private String region
静态属性:
private static String region
此时存储于方法区中,含有自己的内存地址,所有的员工对象持有region的内存地址。
类加载方面的知识点:
- 被
static
修饰的方法或者变量不需要像之前依赖对象.方法()的形式去访问。它是在类被加载之后(静态成员在类加载时加载并初始化然后保存在方法区)就可以通过类名去访问了。静止不动的。不会因为对象多次创建而随之在内存中多次创建(对象公用)。 - 静态不能访问非静态,但是非静态可以访问静态。原因:静态资源可被调用的时机早于非静态资源。
Emp.region = "";
可以直接通过类名访问
用一个static int count
并在每个构造方法里++,则可以打印创建次数。
- main方法的
static
不需要创建对象来调用,可以直接用。a的main中直接b.say();
包
- 包=类+接口
- 不同包中类名可以相同,加上包名以避免冲突
- 包限定访问权限,有权限的才能访问某个包中的类
package name;
- 所有单词字母小写,单词之间.隔开,一般为
com.公司名.项目名.模块名....
(是域名,一般不太会重复)(实际上文件夹分层了)
导包时也可以写类的全名称:
java.util.Scanner input = new java.util.Scanner(System.in);
。
同一个包中的其他类使用时也不用导包
权限修饰符
public
都可以访问protected
其他包不能访问default
只有本类和包能访问,子类都不能private
只有本类中能访问,包内其他类都不能
代码块
- 构造代码块,(直接写在class下的{},不是方法)类中的成员代码块,每次对象创建时执行,且在构造方法之前执行。
- 静态代码块,类中使用
static
修饰的成员代码块。在类加载时执行。程序启动到关闭只执行一次 - 同步代码块。多线程。
- 执行顺序:静态代码块->构造代码块->构造方法
main方法详解
- public 可以被所有操作调用
- static 可以通过类名调用
- void 没有返回值
- main JVM只认这个为程序入口
- String[] args 字符串数组,接受参数(控制台参数,多个)
输出看看:
其实这个数组长度为0,没有输出
这些参数是在执行java命令时传递的。
java Demo1 haha haha hehe
就可以有输出了
问题总结
- 栈中的数据大小与生存期是如何确定的?
- 如果复制对象b2=b1,改变b2的属性,那么最后打印出来的b1的属性也会更改,因为指向相同的引用
- super必须放第一行的原因?