SJDK

141 阅读14分钟

switch

  • A:switch语句的格式
		switch(表达式) {
		      case 值1:
				语句体1;
				break;
			    case 值2:
				语句体2;
				break;
			    …
			    default:	
				语句体n+1;
				break;
	    }
  • B:面试题
    • byte可以作为switch的表达式吗?
    • long可以作为switch的表达式吗?
    • String可以作为switch的表达式吗?
      • switch可作用于char byte short int
      • switch可作用于char byte short int对应的包装类
      • switch不可作用于long double float boolean,包括他们的包装类
        • 不支持long的原因就是 switch 对应的 JVM 字节码 lookupswitch、tableswitch 指令只支持 int 类型。
      • switch中可以是字符串类型,String(JDK1.7之后才可以作用在string上)
      • switch中可以是枚举类型(JDK1.5之后)

代码块

  • A:看程序写结果
		class Student {
			static {
				System.out.println("Student 静态代码块");
			}
			
			{
				System.out.println("Student 构造代码块");
			}
			
			public Student() {
				System.out.println("Student 构造方法");
			}
		}
	
		class Demo2_Student {
			static {
				System.out.println("Demo2_Student静态代码块");
			}
			
			public static void main(String[] args) {
				System.out.println("我是main方法");
				
				Student s1 = new Student();
				Student s2 = new Student();
			}
		}
		Demo2_Student静态代码块
		我是main方法
		System.out.println("Student 静态代码块");
		System.out.println("Student 构造代码块");
		System.out.println("Student 构造方法");
		System.out.println("Student 构造代码块");
		System.out.println("Student 构造方法");

继承

  • A:案例演示
  •   看程序写结果1
      class Fu{
      	public int num = 10;
      	public Fu(){
      		System.out.println("fu");
      	}
      }
      class Zi extends Fu{
      	public int num = 20;
      	public Zi(){
      		System.out.println("zi");
      	}
      	public void show(){
      		int num = 30;
      		System.out.println(num); //30
      		System.out.println(this.num); //20
      		System.out.println(super.num); //10
      	}
      }
      class Test1_Extends {
      	public static void main(String[] args) {
      		Zi z = new Zi();
      		z.show();
      	}
      }
    
      看程序写结果2
      class Fu {
      	static {
      		System.out.println("静态代码块Fu");
      	}
    
      	{
      		System.out.println("构造代码块Fu");
      	}
    
      	public Fu() {
      		System.out.println("构造方法Fu");
      	}
      }
    
      class Zi extends Fu {
      	static {
      		System.out.println("静态代码块Zi");
      	}
    
      	{
      		System.out.println("构造代码块Zi");
      	}
    
      	public Zi() {
      		System.out.println("构造方法Zi");
      	}
      }
    
      Zi z = new Zi(); 请执行结果。
      System.out.println("静态代码块Fu");
      System.out.println("静态代码块Zi");
      System.out.println("构造代码块Fu");
      System.out.println("构造方法Fu");
      System.out.println("构造代码块Zi");
      System.out.println("构造方法Zi");
    

方法重写

  • A:方法重写的面试题
    • Override和Overload的区别?Overload能改变返回值类型吗?

    • overload可以改变返回值类型,只看参数列表

    • 方法重写:子类中出现了和父类中方法声明一模一样的方法。与返回值类型有关,返回值是一致(或者是子父类)的

    • 方法重载:本类中出现的方法名一样,参数列表不同的方法。与返回值类型无关。

    • 子类对象调用方法的时候:

      • 先找子类本身,再找父类。

四种权限修饰符

  • A:案例演示
    • 四种权限修饰符
  • B:结论
  •   			本类	 同一个包下(子类和无关类)	不同包下(子类)	不同包下(无关类)
      private 	Y		
      默认		Y		Y
      protected	Y		Y							Y
      public        Y		Y							Y				Y    
    

成员内部类

  • A:面试题
  •   要求:使用已知的变量,在控制台输出30,20,10。
      
      class Outer {
      	public int num = 10;
      	class Inner {
      		public int num = 20;
      		public void show() {
      			int num = 30;
      			System.out.println(?); num
      			System.out.println(??); this.num
      			System.out.println(???);Outer.this.num
      		}
      	}
      }
      class InnerClassTest {
      	public static void main(String[] args) {
      		Outer.Inner oi = new Outer().new Inner();
      		oi.show();
      	}	
      }
    

==号和equals方法的区别

  • ==是一个比较运算符号,既可以比较基本数据类型,也可以比较引用数据类型,基本数据类型比较的是值,引用数据类型比较的是地址值
  • equals方法是一个方法,只能比较引用数据类型,所有的对象都会继承Object类中的方法,如果没有重写Object类中的equals方法,equals方法和==号比较引用数据类型无区别,重写后的equals方法比较的是对象中的属性

Integer的面试题

  •   看程序写结果
      
      Integer i1 = new Integer(97);
      Integer i2 = new Integer(97);
      System.out.println(i1 == i2); false
      System.out.println(i1.equals(i2)); true
      System.out.println("-----------");
    
      Integer i3 = new Integer(197);
      Integer i4 = new Integer(197);
      System.out.println(i3 == i4); false
      System.out.println(i3.equals(i4)); true
      System.out.println("-----------");
    
      Integer i5 = 97;
      Integer i6 = 97;
      System.out.println(i5 == i6); true 仅限自动装箱
      System.out.println(i5.equals(i6)); true
      System.out.println("-----------");
    
      Integer i7 = 197;
      Integer i8 = 197;
      System.out.println(i7 == i8); false
      System.out.println(i7.equals(i8));true
    

并发修改异常产生的原因及解决方案

  • A:案例演示

    • 需求:我有一个集合,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现。

        List list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("world");
        list.add("d");
        list.add("e");
        
        /*Iterator it = list.iterator();
        while(it.hasNext()) {
        	String str = (String)it.next();
        	if(str.equals("world")) {
        		list.add("javaee");			//这里会抛出ConcurrentModificationException并发修改异常
        	}
        }*/
      
  • B:ConcurrentModificationException出现

    • 迭代器遍历,集合修改集合
  • C:解决方案

    • a:迭代器迭代元素,迭代器修改元素(ListIterator的特有功能add)

    • b:集合遍历元素,集合修改元素

        ListIterator lit = list.listIterator();		//如果想在遍历的过程中添加元素,可以用ListIterator中的add方法
        while(lit.hasNext()) {
        	String str = (String)lit.next();
        	if(str.equals("world")) {
        		lit.add("javaee");	
        		//list.add("javaee");
        	}
        }
      

泛型

  • A:泛型概述
  • B:泛型好处
    • 提高安全性(将运行期的错误转换到编译期)
    • 省去强转的麻烦
  • C:泛型基本使用
    • <>中放的必须是引用数据类型
  • D:泛型使用注意事项
    • 前后的泛型必须一致,或者后面的泛型可以省略不写(1.7的新特性菱形泛型)
    • 声明的ArrayList 变量,在运行时可添加String进去,使用反射。

泛型高级之通配符

  • A:泛型通配符<?>
    • 任意类型,如果没有明确,那么就是Object以及任意的Java类了
  • B:? extends E
    • 向下限定,E及其子类
  • C:? super E
    • 向上限定,E及其父类

三种迭代的能否删除

  • 普通for循环,可以删除,但是索引要--
  • 迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常
  • 增强for循环不能删除

流的标准处理异常代码1.6版本及其以前

  • try finally嵌套

      FileInputStream fis = null;
      FileOutputStream fos = null;
      try {
      	fis = new FileInputStream("aaa.txt");
      	fos = new FileOutputStream("bbb.txt");
      	int b;
      	while((b = fis.read()) != -1) {
      		fos.write(b);
      	}
      } finally {
      	try {
      		if(fis != null)
      			fis.close();
      	}finally {
      		if(fos != null)
      			fos.close();
      	}
      }
    

流的标准处理异常代码1.7版本

  • try close

      try(
      	FileInputStream fis = new FileInputStream("aaa.txt");
      	FileOutputStream fos = new FileOutputStream("bbb.txt");
      	MyClose mc = new MyClose();
      ){
      	int b;
      	while((b = fis.read()) != -1) {
      		fos.write(b);
      	}
      }
    
  • 原理

    • 在try()中创建的流对象必须实现了AutoCloseable这个接口,如果实现了,在try后面的{}(读写代码)执行后就会自动调用,流对象的close方法将流关掉

装饰设计模式

  •   interface Coder {
      	public void code();
      }
      
      class Student implements Coder {
      
      	@Override
      	public void code() {
      		System.out.println("javase");
      		System.out.println("javaweb");
      	}
      	
      }
      
      class HeiMaStudent implements Coder {
      	private Student s;						//获取到被包装的类的引用
      	public ItcastStudent(Student s) {		//通过构造函数创建对象的时候,传入被包装的对象
      		this.s = s;
      	}
      	@Override
      	public void code() {					//对其原有功能进行升级
      		s.code();
      		System.out.println("数据库");
      		System.out.println("ssh");
      		System.out.println("安卓");
      		System.out.println(".....");
      	}
      	
      } 
    

多线程(两种方式的区别)

  • 查看源码的区别:

    • a.继承Thread : 由于子类重写了Thread类的run(), 当调用start()时, 直接找子类的run()方法
    • b.实现Runnable : 构造函数中传入了Runnable的引用, 成员变量记住了它, start()调用run()方法时内部判断成员变量Runnable的引用是否为空, 不为空编译时看的是Runnable的run(),运行时执行的是子类的run()方法
  • 继承Thread

    • 好处是:可以直接使用Thread类中的方法,代码简单
    • 弊端是:如果已经有了父类,就不能用这种方法
  • 实现Runnable接口

    • 好处是:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
    • 弊端是:不能直接使用Thread中的方法需要先获取到线程对象后,才能得到Thread的方法,代码复杂

多线程(死锁)

  • 多线程同步的时候, 如果同步代码嵌套, 使用相同锁, 就有可能出现死锁
    • 尽量不要嵌套使用

        private static String s1 = "筷子左";
        private static String s2 = "筷子右";
        public static void main(String[] args) {
        	new Thread() {
        		public void run() {
        			while(true) {
        				synchronized(s1) {
        					System.out.println(getName() + "...拿到" + s1 + "等待" + s2);
        					synchronized(s2) {
        						System.out.println(getName() + "...拿到" + s2 + "开吃");
        					}
        				}
        			}
        		}
        	}.start();
        	
        	new Thread() {
        		public void run() {
        			while(true) {
        				synchronized(s2) {
        					System.out.println(getName() + "...拿到" + s2 + "等待" + s1);
        					synchronized(s1) {
        						System.out.println(getName() + "...拿到" + s1 + "开吃");
        					}
        				}
        			}
        		}
        	}.start();
        }
      

IO流需要补充 各种stream reader bufferedwriter PrintStream

线程安全的类

  • A:回顾以前说过的线程安全问题
    • 看源码:Vector,StringBuffer,Hashtable,Collections.synchroinzed(xxx)
    • Vector是线程安全的,ArrayList是线程不安全的
    • StringBuffer是线程安全的,StringBuilder是线程不安全的
    • Hashtable是线程安全的,HashMap是线程不安全的

单例设计模式

  • 单例设计模式:保证类在内存中只有一个对象。

  • 如何保证类在内存中只有一个对象呢?

    • (1)控制类的创建,不让其他类来创建本类的对象。private
    • (2)在本类中定义一个本类的对象。Singleton s;
    • (3)提供公共的访问方式。 public static Singleton getInstance(){return s}
  • 单例写法两种:

    • (1)饿汉式 开发用这种方式。
    •   //饿汉式
        class Singleton {
        	//1,私有构造函数
        	private Singleton(){}
        	//2,创建本类对象
        	private static Singleton s = new Singleton();
        	//3,对外提供公共的访问方法
        	public static Singleton getInstance() {
        		return s;
        	}
        	
        	public static void print() {
        		System.out.println("11111111111");
        	}
        }
      
    • (2)懒汉式 面试写这种方式。多线程的问题?
    •   //懒汉式,单例的延迟加载模式
        class Singleton {
        	//1,私有构造函数
        	private Singleton(){}
        	//2,声明一个本类的引用
        	private static Singleton s;
        	//3,对外提供公共的访问方法
        	public static Singleton getInstance() {
        		if(s == null)
        			//线程1,线程2
        			s = new Singleton();
        		return s;
        	}
        	
        	public static void print() {
        		System.out.println("11111111111");
        	}
        }
      
    • (3)第三种格式
    •   class Singleton {
        	private Singleton() {}
        
        	public static final Singleton s = new Singleton();//final是最终的意思,被final修饰的变量不可以被更改
        }
      

简单工厂模式概述和使用

  • A:简单工厂模式概述
    • 又叫静态工厂方法模式,它定义一个具体的工厂类负责创建一些类的实例
  • B:优点
    • 客户端不需要在负责对象的创建,从而明确了各个类的职责
  • C:缺点
    • 这个静态工厂类负责所有对象的创建,如果有新的对象增加,或者某些对象的创建方式不同,就需要不断的修改工厂类,不利于后期的维护
  • D:案例演示
    • 动物抽象类:public abstract Animal { public abstract void eat(); }
    • 具体狗类:public class Dog extends Animal {}
    • 具体猫类:public class Cat extends Animal {}
    • 开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。
  •   public class AnimalFactory {
      	private AnimalFactory(){}
      
      	//public static Dog createDog() {return new Dog();}
      	//public static Cat createCat() {return new Cat();}
      
      	//改进
      	public static Animal createAnimal(String animalName) {
      		if(“dog”.equals(animalName)) {}
      		else if(“cat”.equals(animale)) {
      
      		}else {
      			return null;
      		}
      	}
      } 
    

工厂方法模式的概述和使用

  • A:工厂方法模式概述
    • 工厂方法模式中抽象工厂类负责定义创建对象的接口,具体对象的创建工作由继承抽象工厂的具体类实现。
  • B:优点
    • 客户端不需要在负责对象的创建,从而明确了各个类的职责,如果有新的对象增加,只需要增加一个具体的类和具体的工厂类即可,不影响已有的代码,后期维护容易,增强了系统的扩展性
  • C:缺点
    • 需要额外的编写代码,增加了工作量
  • D:案例演示
  •   动物抽象类:public abstract Animal { public abstract void eat(); }
      工厂接口:public interface Factory {public abstract Animal createAnimal();}
      具体狗类:public class Dog extends Animal {}
      具体猫类:public class Cat extends Animal {}
      开始,在测试类中每个具体的内容自己创建对象,但是,创建对象的工作如果比较麻烦,就需要有人专门做这个事情,所以就知道了一个专门的类来创建对象。发现每次修改代码太麻烦,用工厂方法改进,针对每一个具体的实现提供一个具体工厂。
      狗工厂:public class DogFactory implements Factory {
      	public Animal createAnimal() {…}
              }
      猫工厂:public class CatFactory implements Factory {
      	public Animal createAnimal() {…}
              }  
    

反射(动态代理的概述和实现)

  • A:动态代理概述
    • 代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象。

    • 举例:春节回家买票让人代买

    • 动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理

    • 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象

    • public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

    • 最终会调用InvocationHandler的方法

    • InvocationHandler Object invoke(Object proxy,Method method,Object[] args)

设计模式(模版(Template)设计模式概述和使用)

  • A:模版设计模式概述
    • 模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现
  • B:优点和缺点
    • a:优点
      • 使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求
    • b:缺点
      • 如果算法骨架有修改的话,则需要修改抽象类 1,装饰 2,单例 3,简单工厂 4,工厂方法 5,适配器 6,模版

JDK5新特性(自己实现枚举类)

  • A:枚举概述
    • 是指将变量的值一一列出来,变量的值只限于列举出来的值的范围内。举例:一周只有7天,一年只有12个月等。
  • B:回想单例设计模式:单例类是一个类只有一个实例
    • 那么多例类就是一个类有多个实例,但不是无限个数的实例,而是有限个数的实例。这才能是枚举类。
  • C:案例演示
    • 自己实现枚举类 1,自动拆装箱 2,泛型 3,可变参数 4,静态导入 5,增强for循环 6,互斥锁 7,枚举

###27.14_JDK5新特性(通过enum实现枚举类)

  • A:案例演示
    • 通过enum实现枚举类

JDK5新特性(枚举的注意事项)

  • A:案例演示
    • 定义枚举类要用关键字enum
    • 所有枚举类都是Enum的子类
    • 枚举类的第一行上必须是枚举项,最后一个枚举项后的分号是可以省略的,但是如果枚举类有其他的东西,这个分号就不能省略。建议不要省略
    • 枚举类可以有构造器,但必须是private的,它默认的也是private的。
    • 枚举类也可以有抽象方法,但是枚举项必须重写该方法
    • 枚举在switch语句中的使用

JDK5新特性(枚举类的常见方法)

  • A:枚举类的常见方法
    • int ordinal()
    • int compareTo(E o)
    • String name()
    • String toString()
    • T valueOf(Class type,String name)
    • values()
    • 此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便
  • B:案例演示
    • 枚举类的常见方法

JDK7新特性(JDK7的六个新特性回顾和讲解)

  • A:二进制字面量
  • B:数字字面量可以出现下划线
  • C:switch 语句可以用字符串
  • D:泛型简化,菱形泛型
  • E:异常的多个catch合并,每个异常用或|
  • F:try-with-resources 语句

JDK8新特性(JDK8的新特性)

  • 接口中可以定义有方法体的方法,如果是非静态,必须用default修饰

  • 如果是静态的就不用了

      class Test {
      	public void run() {
      		final int x = 10;
      		class Inner {
      			public void method() {
      				System.out.println(x);
      			}
      		}
      
      		Inner i = new Inner();
      		i.method();
      	}
      	
      }
    
      局部内部类在访问他所在方法中的局部变量必须用final修饰,为什么?
      因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用