23.final关键字(自己的笔记)
由于继承中方法有一个现象:方法重写。
所以,父类的功能,就会被子类给覆盖调。
有些时候,我们不想让子类去覆盖掉父类的功能,只能让他使用。
这个时候,针对这种情况,Java就提供了一个关键字:final
特点:
A:它修饰的类,该类不能被继承(这个类叫最终类,没有子类)。
B:它修饰的方法,该方法不能被重写。
C:它修饰的变量,该变量只能被赋值一次,不能被重新赋值,因为这个变量变成了一个常量。
常量: A:字面值常量"hello",10,true
B: 自定义常量final int x = 10;
面试题:final修饰局部变量的问题。。。。。。。。。。。。。。。。重点
基本类型:基本类型的值不能发生改变。
引用类型:引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。
24.什么时候设计继承:当类与类出现所属关系时。父类私有,子类就拿不到。
25.java只支持单继承,不支持不多继承。
类与类之间是继承关系。
类与接口之间是实现关系。
接口与接口之间是继承关系,而且,接口之间存在多继承。
26.多态。对象多态性。在教室学生,回家就是儿子。在公司就是员工。。。。。重点
好处:提高了程序的扩展性。
思想:通过面向对象的思想,可以指挥对象做事情,如果对象多了,指挥每一个对象,就变得很麻烦。
如何将麻烦的事情简单化呢?对这些对象进行分析并向上抽取,出现了共性类型后,就可以指挥共性类型做事情。
那么,只要是这种共性类型的子类,就可以被指挥。
在程序上的体现:
父类或者接口引用指向了自己的子类对象。
父类或者接口引用接收自己的子类对象。
--------------------------------------------------
多态的好处:(我的j2se笔记)
A:提高了代码的维护性(继承保证)
B:提高了代码的扩展性(由多态保证)
多态的弊端:
父类只能使用自己定义过的方法,
父类不能使用子类的特有功能。
-------------------------------------------
博客园:
多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,
而是在程序运行期间才确定,
即一个引用变量倒底会指向哪个类的实例对象,
该引用变量发出的方法调用到底是哪个类中实现的方法,
必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,
这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,
从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,
让程序可以选择多个运行状态,这就是多态性。
比如你是一个酒神,对酒情有独钟。某日回家发现桌上有几个杯子里面都装了白酒,从外面看我们是不可能知道这是些什么酒,只有喝了之后才能够猜出来是何种酒。你一喝,这是剑南春、再喝这是五粮液、再喝这是酒鬼酒….在这里我们可以描述成如下:
酒 a = 剑南春
酒 b = 五粮液
酒 c = 酒鬼酒
…
这里所表现的的就是多态。剑南春、五粮液、酒鬼酒都是酒的子类,我们只是通过酒这一个父类就能够引用不同的子类,这就是多态——我们只有在运行的时候才会知道引用变量所指向的具体实例对象。
Java实现多态有三个必要条件:继承、重写、向上转型。
继承:在多态中必须存在有继承关系的子类和父类。
重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。
只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。
27.面向对象:
面向过程例子:把大象放冰箱里。开-放-关。从头执行到尾
定义开的方法,定义存放的方法,定义关闭的方法。
面向对象:指挥冰箱 开,指挥冰箱把大象放进去,指挥冰箱把冰箱门关上。
强调的是被操作的事物
先描述冰箱,描述大象
冰箱中定义了开,放,关的行为
只要指挥冰箱做事情,调用它的开方法,再调用放的方法,把
大象作为参数存入,再调用关的方法。
从执行者变成指挥者。
28.面向对象的特征:
1.封装
隐藏实现细节,提高安全性
2.继承
提高了代码复用性,让类与类之间产生了关系
3.多态
增强程序的扩展性
29.多线程(传智播客_2015年Java基础班视频精华版)
进程:正在执行的应用程序
线程:进程的执行单元,是一条执行路径
单线程:一个应用程序只有一条执行路径
多线程:一个应用程序有多条执行路径
多线程的意义:提高应用程序的使用率
多线程的执行具有随机性
多线程的实现方案(自己补齐步骤及代码 掌握)
A:继承Thread类
B:实现Runnable接口
方式1:继承Thread类
1.自定义类MyThread继承Thread类
2.MyThread类里面重写run()方法
为什么呢?
不是类中的所有代码都需要被线程执行,java提供了Thread类中的run()用来包含那些被线程执行的代码。
3.创建对象
4.启动线程
public class MyThread extends Thread{
public void run(){
//一般来说,被线程执行的代码是比较耗时的,所以我们用循环改进
for(int x=0;x<200;x++){
System.out.println(x);
}
}
}
public class MyThreadDemo {
public static void main(String[] args) {
// 创建线程对象
MyThread my = new MyThread();
// 启动线程
// my.run();
// my.run();
// 调用run()方法为什么是单线程的呢?
// 因为run()方法直接调用其实就相当于普通的方法调用,所以你看到的是单线程的效果
// 要想看到多线程的效果,就必须说说另一个方法:start()
// 面试题:run()和start()的区别?
// run():仅仅是封装被线程执行的代码,直接调用是普通方法
// start():首先启动了线程,然后再由jvm去调用该线程的run()方法。
MyThread my = new MyThread();
my.start();
// my.start();
// // IllegalThreadStateException:非法的线程状态异常
// // 为什么呢?因为这个相当于是my线程被调用了两次。而不是两个线程启动。
所以改为如下:
// 创建两个线程对象
MyThread my1 = new MyThread();
MyThread my2 = new MyThread();
//调用方法设置名称
my1.setName("林青霞");
my2.setName("刘意");
my1.start();
my2.start();
}
}
============
为什么要重写run()方法?
因为run()里面封装的是被线程执行的代码
启动线程对象用的是哪个方法
start()
run()和start()方法的区别
run()直接调用仅仅是普通方法
start()先启动线程,再由jvm调用run()方法
------------------------------------------------------------------------------
线程的调度和优先级问题
A:线程的调度
a:分时调度
b:抢占式调度 (Java采用的是该调度方式)
B:获取和设置线程优先级
a:默认是5
b:范围是1-10
---------------------------------------
A:休眠线程:Thread.sleep(1000);
B:加入线程:tj1.join();为了让某些线程执行完毕,别人才可以执行
C:礼让线程:Thread.yield();暂停当前正在执行的线程对象,并执行其他线程。让多个线程的执行更和谐,但是不能靠它保证一人一次。
D:后台线程:设置守护线程:td1.setDaemon(true);该方法必须在启动线程前调用。
E:终止线程(掌握):ts.interrupt();中断线程,把线程的状态终止
----------------------------
线程的生命周期:
A:新建:创建线程对象
B:就绪:有执行资格,没有执行权
C:运行:有执行资格,有执行权
D:阻塞:由于一些操作让线程处于了该状态,没有执行资格,没有执行权。而另一些操作却可以把它给激活,激活后处于就绪状态。
E:死亡:线程对象变成垃圾,等待被回收。
------------
方式2:实现Runnable接口
步骤:
1.自定义类MyRunnable实现Runnable接口
2.重写run()方法
3.创建MyRunnable类的对象
4.创建Thread类的对象,并把C步骤的对象作为构造参数传递
public class MyRunnable implements Runnable{
public void run(){
for(int x=0;x<100;x++){
//由于实现接口的方式就不能使用Thread类的方法了,但是可以间接的使用
System.out.println(Thread.currentThread().getName() +":" + x);
}
}
}
-------
public class MyRunnableDemo{
public static void main(String[] args){
//创建MyRunnable类的对象
MyRunnable my = new MyRunnable();
//创建Thread类的对象,并把C步骤的对象作为构造参数传递
//如果一个参数要的是接口,其实要的是子类对象
Thread t1 = new Thread(my);
Thread t2 = new Thread(my);
t1.start();
t2.start();
}
}
=======================================================================
有了方式1,为什么还来一个方式2?
1.可以避免由于java单继承带来的局限性
2.适合多个相同程序代码去处理同一个资源的情况,把线程同程序的代码、数据有效分离,
较好地体现了面向对象的设计思想。
大部分情况用方式2
==============
电影院卖票案例:
问题:
相同的票出现多次:cpu的一次操作必须是原子性的
还出现了负数的票:随机性和延迟导致的
==============
多线程安全的原因(而且这些原因也是以后我们判断一个程序是否会有线程安全问题的标准)
1.是否是多线程环境
2.是否有共享数据
3.是否有多条语句操作共享数据
如何解决多线程安全问题呢
1和2我们改变不了
我们只能考虑改变3
思想:
把多条语句操作共享数据的代码给包成一个整体,让某个线程在执行的时候,别人不能操作。
同步代码块:
格式:synchronized(对象){
需要同步的代码
}
同步可以解决安全问题的根本原因就在那个对象上。该对象如同锁的功能。
public class SellTicket implements Runnable {
// 定义100张票
private int tickets = 100;
//创建锁对象
private Object obj = new Object();
@Override
public void run() {
while (true) {
synchronized (obj) {
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票");
}
}
}
}
}
public class SellTicketDemo {
public static void main(String[] args) {
// 创建资源对象
SellTicket st = new SellTicket();
// 创建三个线程对象
Thread t1 = new Thread(st, "窗口1");
Thread t2 = new Thread(st, "窗口2");
Thread t3 = new Thread(st, "窗口3");
// 启动线程
t1.start();
t2.start();
t3.start();
}
}
-------------------------------------------------------
同步的前提:
多个线程
多个线程使用的是同一个锁对象
同步的好处:
同步的出现解决了多线程的安全问题
同步的弊端:
当线程相当多时,因为每个线程都会去判断同步上的锁,这是很耗费资源的
无形中会降低程序的运行效率。
--------------------------
同步代码块的锁对象是谁呢:
任意对象
同步方法的格式及对象问题
把同步关键字加在方法上
这里的锁对象是this
静态同步方法
把同步加在方法上。
这里的锁对象是当前类的字节码文件对象(反射再讲字节码文件对象)
例如:synchronized(SellTicket.class)
-------------------
线程安全的类:
StringBuffer sb = new StringBuffer();
Vector<String> v = new Vector<String>();
Hashtable<String,String> h = new Hashtable<String,String>();
如何把一个线程不安全的集合类变成一个线程安全的集合类
用Collections工具类的方法即可。
List<String> list1 = new ArrayList<String>();//线程不安全的
List<String> list2 = Collections.synchronizedList(new ArrayList<String>());//线程安全
=====================
JDK5中LOCK的使用:
虽然我们可以理解同步代码块和同步方法的锁对象问题,
但是我们并没有直接看到在哪里加上了锁,在哪里释放了锁,
为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象LOCK
void lock()获取锁
void unlock()释放锁
ReentrantLock是Lock的实现类
public class SellTicket implements Runnable {
// 定义票
private int tickets = 100;
//定义锁对象
private Lock lock = new ReentrantLock();
@Override
public void run() {
while (true) {
try{
//加锁
lock.lock();
if (tickets > 0) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()
+ "正在出售第" + (tickets--) + "张票");
}
}finally{
//释放锁
lock.unlock();
}
}
}
}
---------------------------------------
同步弊端:
效率低
如果出现了同步嵌套,就容易产生死锁问题
死锁问题及其代码
是指两个或者两个以上的线程在执行的过程中,因争夺资源产生的一种互相等待的现象。
================
线程间通信的问题:不同种类的线程间针对同一个资源的操作
重点:。。。。。。。!!!!!!有时间多研究几遍!!!!
思想:如果想把一个数据在多个类中共享使用,方法有很多
今天讲一种:
在外界把这个数据创建出来,通过构造方法传递给其他的类
-------------------------------
加锁:
注意事项:不同种类的线程都要加锁
不同种类的线程加的锁必须是同一把
------------------------
等待唤醒机制:
Object类中提供了三个方法:
wait():等待
notify():唤醒单个线程
notifyAll():唤醒所有线程
为什么这些方法不定义在Thread类中呢?
这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象。
所以,这些方法必须定义在Object类中。
=========多线程有时间重点研究,高级软件工程师!!!!!
多线程面试:
1:多线程有几种实现方案,分别是哪几种?
两种。
继承Thread类
实现Runnable接口
扩展一种:实现Callable接口。这个得和线程池结合。
2:同步有几种方式,分别是什么?
两种。
同步代码块
同步方法
3:启动一个线程是run()还是start()?它们的区别?
start();
run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
start():启动线程,并由JVM自动调用run()方法
4:sleep()和wait()方法的区别
sleep():必须指时间;不释放锁。
wait():可以不指定时间,也可以指定时间;释放锁。
5:为什么wait(),notify(),notifyAll()等方法都定义在Object类中
因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
而Object代码任意的对象,所以,定义在这里面。
6:线程的生命周期图
新建 -- 就绪 -- 运行 -- 死亡
新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡
建议:画图解释。
设计模式:
(1)面试对象的常见设计原则
单一
开闭
里氏
依赖注入
接口
迪米特
(2)设计模式概述和分类
A:经验的总结
B:三类
创建型
结构型
行为型
(3)改进的设计模式
A:简单工厂模式
又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例。
优点:客户端不需要再负责对象的创建,从而明确了各个类的职责。
缺点:这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些
对象的创建方式不同,就需要不断的修改工厂、不利于后期维护。
B:工厂方法模式
工厂方法模式中抽象工厂类负责定义创建对象的接口,
具体对象的创建工作由继承抽象工厂的具体类实现。
优点:客户端不需要再负责对象的创建,从而明确了各个类的职责,
如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,
不影响已有的代码,后期维护容易,增强了系统的扩展性。
缺点:需要维护额外的编写代码,增加了工作量。
------------------
面试经常问!!!!!!!!
C:单例模式(掌握)
单例模式就是要确保在内存中只有一个对象,该实例必须自动创建,并且对外提供。
优点:在系统内存中只存在一个对象,因此可以节约系统资源,
对于一些需要频繁创建和销毁的对象单例模式无疑可以提高系统的性能。
缺点:没有抽象层,因此扩展性很难
职责过重,在一定程序上违背了单一职责。
a:饿汉式
b:懒汉式
a:饿汉式:类一加载就创建对象
1.构造方法私有
2.在成员位置自己创建对象
3.通过一个公共的方法提供访问
public class Student{
//构造私有
private Student(){}
//自己造一个
//因为静态方法只能访问静态成员变量
private static Student s = new Student();//静态的,随着类的加载而加载,类加载的时候就造了对象
//为了不让外界直接访问修改这个值,加private
//提供公共的访问方式,这个方法你能直接调吗,非静态必须要造对象调,而在外界又造不了对象!!
//为了保证外界直接使用该方法,加静态
public static Student getStudent(){
return s;
}
}
public class StudentDemo{
public static void main(String[] args){
//通过单例如何得到对象呢
Student s1 = Student.getStudent();
Student s2 = Student.getStudent();
System.out.println(s1==s2);//true
}
}
b:懒汉式:用的时候才去创建对象
public class Tearcher{
private Tearcher(){
}
private static Tearcher t = null;
public static Tearcher getTearcher(){
if(t == null){
t = new Tearcher();
}
return t;
}
}
--------------
面试题:单例模式的思想是什么?请写一个代码体现。
思想:保证类在内存中只有一个对象
开发:用饿汉式,是不会出问题的单例模式
面试:用懒汉式,可能会出问题的单例模式
A:懒加载思想(延时加载)
B:线程安全问题
a:是否多线程环境 是
b:是否有共享数据 是
c:是否有多条语句操作共享数据 是
改进:加上synchronized
public class Tearcher{
private Tearcher(){
}
private static Tearcher t = null;
public synchronized static Tearcher getTearcher(){
if(t == null){
t = new Tearcher();
}
return t;
}
}
31.线程的安全问题:多线程,在操作同一个变量造成。
一个线程先执行完,第二个线程再执行。
32.多线程:
创建方式
1)继承Thread类。
2)实现Runnable接口。避免了单继承的局限性。
因为多线程具备一个随机性,就会容易出现线程安全问题。
导致该问题的原因通常是:多条语句同时在操作成员数据,这是这些语句被多个线程分开执行,就会出现安全问题。
解决方式:
将多条语句在同一时间被一个线程一次执行完,在让另一个线程执行。
通过同步代码块来完成部分代码的同步。synchronized(对象){}
同步的出现
好处:解决了多线程安全问题。
弊端:对资源有一定消耗,降低了程序的效率。
如果同步出现嵌套还容易引起死锁。
33.StringBuffer:
它是一个容器,可以对字符串进行修改。长度可变。
添加:append(data)
删除:delete(start,end)
deleteCharAt(index)
插入:insert(index,data);
反转:reverse():
修改:setCharAt(index,data)
替换:replace(start,end,String)
什么时候用缓冲区呢?
当要操作的元素类型不一致,但最终都会转成字符串的时候。就使用StringBuffer.
JDK1.5版本的时候,出现了StringBuilder.该对象的用法和StringBuffer一致的。
但是对于多线程操作有所不同,StringBuffer是线程安全的,StringBuilder是线程不安全的。
面试题2
最新推荐文章于 2022-04-18 09:58:13 发布