全面学习OOP面向对象编程(含代码和面试题)

1 篇文章 0 订阅
0 篇文章 0 订阅

这一篇文章我将和大家一起回顾一下OOP面向对象的相关知识,前几天和女朋友分手之后就一直想好好整理一下这部分的内容(开个玩笑哈哈)内容大概共分为7块供大家一起讨论学习,如果有不对的地方欢迎大家指正、讨论。(建议收藏哦,确实比较全面2333)


java语言基础:

开发环境

  1. 搭建java开发环境

    1. 下载并安装JDK
    2. 配置环境变量
      1. JAVA_HOME:jdk的安装路径
      2. path:jdk–>bin的路径
      3. classpath:.
  2. JDK,JRE,JVM

  3. java程序的运行机制:先编译后运行

变量:

  1. 变量的声明: 数据类型 变量名称;
  2. 变量的初始化:第一次赋值
  3. 变量的访问:获取变量中的值或给变量赋值
注意点:
  1. 变量的命名:4点
    1. 是由字母,数字,_,$组成,数字不能开头
    2. java中严格区分大小写,不能使用java关键字/保留字
    3. 见名知意,驼峰命名法
    4. java中不建议使用中文

基本数据类型:8种

  1. byte 1字节
  2. short 2字节
  3. int 4字节
  4. long 8字节
  5. float 4字节
  6. double 8字节
  7. boolean 1字节
  8. char 2字节
整数类型:
  • int,long:

    • 赋值时注意数据溢出,java中给出一个整数默认是int类型,如果要定义long类型的变量,赋值时若该值超过了int的范围,需要+L/l

    • byte,short同样需要注意数据溢出

    • 注意点:如果是整数直接量之间的运算并赋值,编译器可以进行优化,将结果优化成想要的数据类型

        byte b = 1+2;
      
  • 浮点类型:

    • float,double精度问题
    • float类型定义变量,赋值时值后需要+F/f,JAVA中给出小数,默认是double类型
    • double不能用于做精确运算,如要做精确运算,使用BigDicaml类来操作
  • char:占用2个字节,保存在内存中的值是该字符对应的unicode码值(整数)

    • 赋值: ‘’ 整数 ‘\u4e00’
  • 类型转换:

    • 自动转换: 小转大
    • 强制转换: 大转小

    注意点:char类型可以自动转换为int类型,但是不能和byte,short进行自动转换,若需要,可以进行强制转换

  • 不同数据类型间的运算:

    • 不同数据类型间进行运算,最后的结果的数据类型一定是和运算中最高的数据类型保持一致的
    • byte,short,char类型间进行运算,都是先提升为了int类型,再运算的,所以最后的结果一定int类型的
      • 注意点:编译器优化问题

          byte b = 1+2;  //编译正确
          byte b = b1+3;  //编译错误
        

    java中的数据类型总体可以分为2种:
    基本数据类型
    引用类型

运算符:

  1. 算术运算符
    1. ++ –
      1. 若i++ ;是先复制,后运算;若++i:是先运算,后赋值
  2. 关系运算符
  3. 逻辑运算符:
    1. && || !
    2. 注意短路问题
  4. 赋值运算符:
      • += -= *= /= %=
    1. 注意赋值运算符自带强转功能

       byte  b= 3;
       b += 3;  //正确
       b = b+3;  //编译错误的
      
  5. 字符串连接运算符 +
  6. 三目运算符:
    1. 数据类型 变量 = 表达式(boolean)?表达式1:表达式2;

分支结构:2种

  1. if…else:用于做范围判断分支
  2. switch…case:用于做精确判断分支
    1. 参数类型只能是int,String,enum
    2. 每条分支的最后加+break;若不加,将顺序往后执行,直到遇到break为止

循环结构:3种

  1. while循环

  2. do…while循环

  3. for循环

  4. 死循环:3种循环都能实现,有些场景是需要死循环来实现的

  5. break和continue的区别:

    1. break:跳出当前循环
    2. continue:跳出本次循环,继续下次循环
    3. return关键字作用于方法中,可以单独使用,若单独使用,执行到此关键字,跳出方法
  6. 嵌套循环:

    1. 考算法

基本类型数组:

  1. 数组的声明:2种

    1. int[] ary; 建议使用
    2. int ary[];
  2. 数组的初始化:3种

    1. int[] ary = new int[length];
    2. int[] ary = {1,2,3};
      1. 此种方式初始化必须在声明的同时进行
    3. int[] ary = new int[]{1,2,3};
  3. 数组的访问:

    1. 通过下标访问数组元素—注意下标越界问题
    2. 遍历数组 – for循环实现
  4. 数组的复制:

    1. System.arraycopy(Object src,int srcPos,Object dest,int destPos,int length);void

    2. Arrays.copyOf(Object src,int newLength):T[]

      1. 常用于做数组的扩容/缩容

      两种方式相比较而言,第一种更灵活,第二种经常用于做扩容/缩容操作

  5. 数组的排序:
    Arrays.sort(T[])

     Arrays类中常用方法:
     	Arrays.copyOf(Object src,int newLength)
     	Arrays.sort(T[])
     	Arrays.toString(T[])
    

排序算法:

  • 冒泡排序 – 必须掌握的

    考试内容:使用冒泡对数组进行排序 – 代码实现要求必须会

方法:5部分

  • 修饰符 返回值类型 方法名(参数列表){方法体}
    1. 返回值类型:
      • 方法若有返回值类型,可以是基本数据类型,也可以是引用类型;方法体中一定有return + 表达式/变量/val值
      • 没有返回值:void
不论方法有没有返回值类,return都可以单独使用(作用:跳出当前方法)
  • 方法名:见名知意,驼峰命名

  • 参数列表:

    • 参数类型:形参,实参
      • 可变参数:int…is – 4点注意点
        1. 参数列表中若有可变参数,一定是位于最后
        2. 参数列表中最多只能有一个可变参数
        3. 可变参数底层是数组,访问方式和数组相同
        4. 可变参数底层是数组,所以可以将一个数组作为参数传给可变参数
注意点:java中的参数传递都是值传递(面试题)

猜字符游戏

  • 得分:总分100,猜错一次扣10分

  • 升级版本 – 作业
    升级内容:

    1. 生成的字符数组长度由用户决定
    2. 添加对输入字符串的长度判断
      • 用户决定生成的字符数组的长度为n,接受用户输入的字符串,添加对此的判断:
        • 若用户输入的字符串的长度!=n,给出提示"输入长度有误,请重新输入!",此时算猜错一次.
    3. 添加对输入次数的判断:
      • 总分100分,最多能答错10次,若现在已经答错10次,再次输入,给出提示"机会已用完!",程序结束
  • 猜字符游戏的思路:

    • 进入游戏,给出提示"欢迎进入猜字符游戏…"
    • 由用户输入目标字符数组的长度 - n
    • 生成目标字符数组 – generate(n)
    •   public char[] generate(int n):
        	char[] letters = {26个英文字母};
        	//flag数组中的每个元素默认表示letters中的每个字符没被取,若某个字符被取走了,
        	此时对应下标对位的flag数组中的元素置为true
        	
        	boolean[] flag = new boolean[letters.length];
        	char[] standard = new char[n];
        	//为standard数组生成n个字符
        	for(int i=0;i<standard.length;i++){
        		int index;
        		do{
        			index = (int)(Math.random()*26);
        		}while(flag[index]);  //若为true,表示字符被取,应重新生成随机数字
      
        		standard[i] = letters[index];
        		flag[index] = true;
        	}
        	return standard;
      
    • 接收用户输入的字符串
      • 判断是否是"EXIT",若是:退出程序 return
      • 如果不是"EXIT",判断输入的字符串长度是否正确:若不正确,提示"长度错误,请重新输入"
        • 此时算做错误1次,要扣分的
        • 若正确:此时进行内容判断
          • String -->char[]

            • String类中的方法:toCharArray():char[]
          • check(char[] input,standard)

              public int[] check(char[] input,char[] standard):
              	int[] result = new int[2];
              	//result[0]:统计答对的字符个数(不统计位置)
              	//result[1]:统计答对的位置正确的字符个数
              	for(int i=0;i<standard.length.i++){
              		for(int j=0;j<input.length;j++){
            
              			if(standard[i]==input[j]){
              				result[0]++;
              				if(i==j){
              					result[1]++;
              				}
              				break;
              			}
              		}
              	}
            
          • 对check结果进行分析:

            • 若result[1]==n;全对,给出得分,程序结束
            • 否则,给出提示,猜对几个字符,继续输入(算答错一次,扣10分)
              用户继续输入之前,进行机会是否用完判断,

OOP:Object oriented programming

  • java是面向对象的语言

  • 面向过程:代码编写更接近计算机的执行方式

  • 面向对象:代码编写接近人的思维方式

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qZnjMday-1583038438619)(1.png)]

类和对象

  • 类:是一类事物的模板

      eg: 人是一个种群,不是对象,但是张三是一个对象,李四也是一个对象
      class Person{
      	String name;
      	int age;
      	double height;
      	double weight;
    
      	public void walk(){..}
      	public void eat(){....}
      }
    

    类的成员:
    属性
    方法

  • 对象:经由类这个模板创建出来的一个具体的实例

    new Person() - 张三
    new Person() - 李四

    • 对象的创建:new 类名();
    • 对象的使用: 通过引用来访问对象内部的数据和方法
      • Person per = new Person();
      • per.属性 = val;
      • String name = per.属性;
      • per.方法()
注意点:
  1. 类中的非static的成员变量和方法都是属于对象的,调用时必须通过对象来调用

     eg:Scanner sc = new Scanner(System.in);
     	String name = sc.next();	
     问题:
     class T{
     	main:
     	 调用test()
     	 T t = new T();
     	 t.test();
    
     	void test(){...}
     }
    
  2. java程序运行后所有的数据都要保存到内存中,而创建的对象保存在内存中的堆中;

    1. JVM内存分成三块区域:
      1. 栈:保存局部变量

      2. 堆:保存对象

        Person per = new Person();

在这里插入图片描述

  1. 非static的成员变量是属于对象的,每新创建一个对象,这些成员变量都会进行一次默认初始化

    在这里插入图片描述

  2. 数组是对象

面试题:

  1. 下列说法错误的是( BCD)

     A. 数组是一种对象
     B. 数组属于一种原生类
     C. int number=[]={31,23,33,43,35,63}
     D. 数组的大小可以任意改变
    
     原生类:java中为8种基本数据类型提供的包装类
    
  2. 关于下列代码说法正确的是:A

     public class A {
         public int counter = 0; 
         public static int getInstanceCount() { 
             return counter;   //编译错误
         } 
        
         public static void main(String[] args) { 
             A a1 = new A(); 
     		a1.counter++;
             A a2 = new A(); 
     		a2.counter--;
             A a3 = new A();
     		a3.counter+=2;
             System.out.println(A.getInstanceCount()); 
         } 
     }
     A.该类编译失败
     B.输出:1
     C.输出:3
     D.输出:0
    
  3. 下面程序运行的结果是 (C)

     Public class A {
         int a = 0 
         int c = 0
         do{
              --c
         }while(a>0){
                 Shystem.out.println(c)
           }
     }
     A 0
     B -1
     C 编译错误
     D 无法计算
    
     考点:do..while循环是写在方法中的
    
  4. 阅读以下代码,程序输出的结果是什么

     public class Test{
     	public static void main(String[] args){
     		int a = 4;
     		char[] chs = {'a','b','c'};
     		Test test = new Test();
     		test.change(a,chs);
     		
     		System.out.println(a);
     		System.out.println(Arrays.toString(chs));
     	}
     	public void change(int a,char[] chs){
     		a = 10;
     		chs[0] = 'g';
     	}
     }
    
     4  gbc
     考点:
     	1.内存管理
     	2.java中的参数传递都是值传递
    

在这里插入图片描述

  1. 作业:猜字符游戏的升级版 – 自己做

     /**
      * 猜字符游戏升级版
      * 	升级点:
      * 		1.生成的目标字符数组长度由用户决定
      * 		2.对用户输入的字符串长度做出判断
      * 		3.对用户猜错的次数做限制,共100分,最多能猜错10次
      * @author Admin
      *
      */
     public class GuessLetterGameUpper {
     	public static void main(String[] args) {
     		Scanner scanner = new Scanner(System.in);
     		int score=0,count=0;   //count表示猜错的次数
     		System.out.println("欢迎进入猜字符游戏:");
     		System.out.println("请输入目标字符的长度:");
     		int n = scanner.nextInt();
     		char[] chs = generate(n);
     		
     		System.out.println(Arrays.toString(chs));
     		
     		while(true) {
     			//是否有机会输入
     			if(count>9) {
     				System.out.println("机会已用完,正确答案是:"+Arrays.toString(chs)+",请重新开始程序!");
     				break;
     			}
     			System.out.println("请输入猜测的字符串:");
     			String line = scanner.next().toUpperCase();
     			//判断是否为exit,长度是否为5
     			if("EXIT".equals(line)) {
     				System.out.println("退出程序,欢迎下次光临!");
     				//结束程序
     				break;
     			}
     			if(line.length()!=n) {
     				System.out.println("输入长度有误,请重新输入!");
     				count++;
     				continue;
     			}
     			char[] input = line.toCharArray();
     			int[] result = check(chs, input);
     			
     			if(result[1]==n) {  //表示猜对了
     				score = 100 - 10*count;
     				System.out.println("恭喜你,猜对了,得分是:"+score);
     				break;
     			}else {
     				System.out.println("猜错了,其中猜对的字符个数是:"
     			+result[0]+",其中,位置正确的有:"+result[1]+"个");
     				count++;
     				continue;
     			}
     		}
     		scanner.close();	
     	}
     	
     	//生成标准字符数组
     	public static char[] generate(int n) {
     		char[] chs = {'A','B','C','D','E','F','G',
     				'H','I','J','K','L','M','N','O','P',
     				'Q','R','S','T','U','V','W','X','Y','Z'};
     		char[] dest = new char[n];  //char \u0000
     		boolean[] flag = new boolean[chs.length];
     		//生成5个随机字符
     		for(int i=0;i<dest.length;i++) {
     			//随机生成下标
     			int index;
     			do {
     				index = (int)(Math.random()*chs.length);
     			}while(flag[index]==true);
     			dest[i] = chs[index];
     			flag[index] = true;
     		}
     		return dest;
     	}
     	
     	//校验用户输入的值
     	public static int[] check(char[] standard,char[] input) {
     		int[] result = new int[2]; //第一个元素表示猜对的字符个数,第二个元素表示位置正确的个数
     		for(int i=0;i<standard.length;i++) {
     			for(int j=0;j<input.length;j++) {
     				if(standard[i]==input[j]) {
     					//字符猜对了
     					result[0]++;
     					if(i==j) {
     						result[1]++;
     					}
     					break;
     				}
     			}
     		}
     		return result;
     	}
     }
    

<2>

方法重载:overload

  • 什么是方法重载?
    • 在同一类中,存在多个方法名相同,参数列表不同的方法

    • 问题:参数列表不同可以有哪些不同

      • 可以是数量不同
      • 可以是数量相同,但是参数类型不同
      • 可以是数量相同,类型也相同,但是顺序不同
    • 问题:方法重载和方法的返回值类型,以及修饰符有关吗?

      • 无关,方法的重载只和方法签名有关

      • 方法签名:方法名+参数列表

          eg:以下几个方法是否构造重载?
          	class Test{
          		public String demo(){...}
          		public void demo(){....}
          		public int demo(int a){...}
          	}
        
          	1和2  --不构成
          	1和3  --构成
          	2和3  --构成
        

构造器–重点(考点)

语法

修饰符 类名(){}

参数列表可以有参数,也可以没有参数

构造器的分类

  • 无参构造器

  • 有参构造器

      常见用法:
      	class T{
      		int age;
      		String name;
    
      		public T(){}  //无参
      		public T(int age,String name){  //有参 - 用于给成员变量赋值
      			this.age = age;
      			this.name = name;
      		}
      	}
    
  • 注意点:

    • 一个类中最多只能有一个无参构造方法,可以没有

      • 没有的场景:人为生成有参构造方法,而没有生成无参构造方法
      • 若一个类中没有人为生成构造方法,java会默认提供一个无参构造器
    • 一个类中有参构造方法可以有多个

      • 通常用于做成员变量的初始化
    • 类中的无参构造器和有参构造器构成了方法的重载

构造器的作用:初始化

问题:
	class T{
		int a = 3;
		T(){  //也完成了成员变量的初始化
			
		}

		public void init(){
			//进行初始化一些数据
		}
	}

在这里插入图片描述

断点:Debug:

  • 用于完成项目中错误的排查

强调点:

  1. 无参构造器是用于初始化,可以将一些初始化的内容写到构造器中
  2. 若成员变量位置进行了人为初始化,那么这个初始化是在无参构造器中完成的。
  3. 创建对象和构造方法的执行顺序:先创建对象,对象创建之后才执行构造方法完成初始化

this

  • 出现在了有参构造方法中

  • this是一个引用,指向了调用所在方法的对象

    • 通过对象调用某个方法时,会隐式的传递一个对象(调用此方法的对象)过去
  • this作用于方法体中的,在没有歧义的情况下,this可以省略

      class T{
      	int a;
        	public void test(){
      		this.demo();  //this可以省略
      		this.a = 3;   //this可以省略
      	}
      	public void demo(){
    
      	}
      }
    
      不可省略的场景:
      	
      class T{
      	int age;
      	String name;
    
      	T(int age,String name){
      		this.age = age;
      		this.name = name;
      	}
      }
    
  • this不可以用于static方法体中

    • static方法是属于对象的吗,调用时是需要通过对象调用吗? 不是属于对象的,调用通过类名调用

    • 若现在要调用一个static方法,此时不需要通过对象调用,此时隐式传递的对象存在吗? 不存在

    • 所以,static方法体中没有this

  • this关键字的使用:

    • this.实例变量
    • this.实例方法
    • this() – 调用无参构造方法
    • this(参数) – 调用有参构造方法

==和空指针问题

  • == 两边是引用类型,此时的作用是比较2个引用是否指向同一对象

      class Point{
      	int x;
      	int y;
    
      	Point(){}
      	Point(int x,int y){
      		this.x = x;
      		this.y = y;
      	}
    
      	main:
      		Point p1 = new Point(20,20);
      		Point p2 = new Point(20,20);
      		p1==p2;   ?  false
      		
      }
    
  • 空指针问题:

    • 引用.实例变量/实例方法;
    • 若此时引用为null,此时会报NullPointerException()

面试题:

  1. 现有代码如下,以下哪些选项是正确的(ace)

     class Test{
     	public String methodA(int a,String str){
     			return "方法A";
     	}
     	//插入代码处
     }
    
     A. public void methodA(byte b,String str){}
     B. public String methodA(int m,String k){return ""} //参数列表不同只看类型和顺序
     C. public String methodA(int a){return ""}
     D. public int methodA(int a,String str){return 1}
     E.  public String methodA(String str,int x){return ""}
    
    
     test(){
     	methodA(5,""); --调用第一个方法
     	//因为5默认是int类型
     	byte b = 3;
     	methodA(b,"")  //调用参数是byte类型的方法
     }
    
     考点:方法重载:只看方法名(相同)和参数列表(不同的)
    
  2. (单选)下列代码的输出结果是:©

     //包装类:8种基本数据类型,Java中为8种基本数据类型都提供了对应的包装类
     long  -- Long:完成对long类型的一些操作(方法)
     int  -- Integer
     short - Short
    
     注意:可以将基本数据类型变量直接赋值给对应的引用类型
     	long l1 = 34L;
     	Long  l = l1;
     	short s = 3;
     	Short s1 = s;
    
     public class Yikes {
         public static void go(Long n) { 
             System.out.println("Long"); 
         } 
         public static void go(Short n) {
             System.out.println("Short");
         } 
         public static void go(int n) {
             System.out.println("int"); 
         } 
         public static void main(String[] args) {
             short y = 6; 
             long z = 7; 
             go(y);   //此处该调用哪个方法? short可以自动提升为int,也可以自动转换为Short
     				//此时采用就近原则(哪种转换更快/更便捷,就哪个近)
     			y -->int  :更便捷的
     			y -->Short:稍微复杂/慢一点
             go(z);   //Long
         } 
     }
     A.Long Long
     B.Short Long
     C.int Long
     D.int int
    
  3. 下列说法正确的有(C)

     A、class中的constructor 不可省略  //若一个类种没有有参,此时无参可以省略
     B、constructor必须与class同名,但方法不能与class同名
     C、constructor是在对象创建后进行初始化的
     D、一个class只能定义一个constructor
    
  4. 以下说法正确的是(CD)

     A. static方法中可以通过this调用实例方法 //static方法中没有this
     B. static方法中可以直接访问该类中的实例变量  //不可以
     C. 实例方法中可以使用this访问本类中的实例变量和实例方法 
     D. 实例方法中可以调用本类中的static方法,也可以访问本类中的static变量  //可以的,但是不建议这么做的
    
     		class T{
     			static int a = 4;
     			static void test(){}
     			void demo(){
     				输出a;
     				test();
     			}
     		}
    
     总结:static方法不能直接访问非static成员,但是非static方法可以直接访问static的,但是不建议
    
  5. 给出下面的代码段,在代码说明//assignment 处写下如下哪几个代码是正确的?(cd)

     public class Base {
         int w, x, y, z;
     	public Base(int a, int b)  {
     	       x=a; y=b;
     	}
     	public Base(int a, int b, int c, int d)  {
     	    //assignment
     	}
     }
     
     A Base(a, b);  //语法错误  Java中不允许在构造方法中直接通过构造方法名调用构造方法
     B x=a, y=b;  //应该用;隔开
     C x=a; y=b;
     D this(a,b);
    
     Java中若在构造方法/普通方法中通过方法名调用方法,调用到的一定是普通方法
    

<3>

引用类型数组

  • 数组中的元素类型若是引用类型,那么这个数组就是引用类型数组

  • 数组是对象,数组可以作为引用类型

  • 数组中的元素可以是数组 - 多维数组

    • 二维数组 - 数组的数组
    • 在内存中的保存形式

    问题:数组中的每个元素指向的数组长度可以是不同的.此时需要注意:
    数组的初始化就不可以使用 以下方式:
    int[][] ary = new int[3][2];

      此时应该这样初始化:
      	int[][] ary = {{2,3},{1,2,3},{1}}
    
    • 二维数组的遍历:
      for(int i=0;i<ary.length;i++){
      //ary[i] //指向第二维的数组
      for(int j=0;j<ary[i].length;j++){
      int a = ary[i][j];
      System.out.println(ary[i][j]);
      }
      }

继承,super

  1. 继承:

    1. 实现方式:extends 子类 extends 父类
    2. 继承的特点:2点
      1. 传递性
      2. 单继承:
        1. java中类的继承是单继承的
          1. 即一个子类只能有一个父类,反之,一个父类是可以由多个子类的
    3. 继承中构造方法的调用问题
      1. 创建子类对象,会先调用父类中的构造方法,再调用子类中的构造方法

         class Super{
         	public Super(){
         		System.out.println("父类中的构造方法");
         	}
         } 
        
         class Sub extends Super{
         	public Sub(){
         		super();
         		System.out.println("子类中的构造方法")
         	}
         }
        
         class Test{
         	main:
         		new Sub();
         }
        
    4. 继承中不继承的成员:
      1. 构造方法
      2. 私有成员 – private
      3. static成员

super:

  • 是一个引用,指向父类的对象
  • 用法:
    • super.成员变量

    • super.实例方法

    • super() :调用父类中的无参构造方法

    • 注意:在子类构造方法中默认会调用父类的无参构造方法,但是我们可以人为调用父类中的有参构造方法

        案例:
        	class SuperCls{
        		int age;
      
        		public SuperCls(int age){
        			this.age = age;
        			//执行其他代码
        		}
        	}
      
        	class SubCls extends SuperCls{
        		public SubCls(){
        			super(3);
        			//要求先初始化的内容是父类中有参构造方法中初始化的内容
        			//其他的初始化
        		}
        	}
      

向上造型

  • 通过父类的引用指向子类对象
    • FlyingObject obj = new AirPlane();

        class Person{
        	String name;
        	int age;
        }
        class Student extends Person{
        	int id;
        }
      
        Person per = new Student();
        per.父类中的成员
      
    • 注意:通过引用只能访问到父类中的成员,访问不到子类中的

    • 向上造型的缺点:

      • 访问不到子类中特有的成员 – 向下造型

面试题

  1. 已知如下代码:

     1: class Example{
     2:     String str;
     3:     public Example(){  
     4:         str= "example";
     5:     }
     6:     public Example(String s){
     7:         str=s;
     8:     }
     9:} 
     10: class Demo extends Example{
     11: }
     12: public class Test{
     13:    public void f () {
     14:        Example ex = new Example("Good");
     15:        Demo d = new Demo("Good");
     16:    } }
     哪句语句会导致错误?( E)
    
     A、line 3    B、line 6    C、line 10   D、line 14    E、line 15
    
  2. 以下哪些是正确的(A)

     class Person{}
     class Student extends Person{}
     class T{
     	public static void main(String[] args){
     		T t = new T();
     		//插入代码处
     	}
    
     	public void demo(Person per){}
     }
     考点:向上造型
     A. t.demo(new Student());
     B. t.demo(3);
     C. t.demo("hello");
     D. t.demo();
    
  3. 以下代码是否编译正确?

     public class Test{
     	
     }
     public class Sub extends Test{
     	public Sub(){
     		System.out.println("子类的构造方法");
     		super();        //编译错误,super()一定是位于构造方法第一行的
     		System.out.println("执行结束");
     	}
     }
    
  4. 以下代码是否编译正确?

     class Super{
     	int age;
     	public Super(int age){
     		this.age = age;
     	}
     }
     class Sub extends Super{
     	String name;
     	public Sub(String name){
     		super();           //编译错误,父类中此时没有无参构造方法
     		this.name   = name;
     	}
     }
    
  5. 以下代码是否编译正确?

     class Super{
     	int a;
     	int b;
    
     	public Super(int a,int b){
     		this.a = a;
     		this.b = b;
     	}
     }
     class Sub extends Super{
     	int a,b,c,d;
     	public Sub(int a,int b,int c,int d){
     		this(a,b);  //编译错误,这样写表示要调用本类中的构造方法
     		this.c = c;
     		this.d = d;
     	}
     }
    
  6. 以下代码的输出结果是什么?

     class  T{
     	main:
     		int a = 10;
     		int[][] ary = {{1,2},{4,7,8}};
     		T t = new T();
     		t.change(a,ary);
     		输出a  ?  10
     		输出ary  ?   {{1,5},{4,7,8}} 
    
     	void change(int a,int[][] ary){
     		a = 4;
     		ary[0][1] = 5;
     	}
     }
    

在这里插入图片描述

  1. 打印杨辉三角形 – 算法题

     1
     1 1
     1 2 1
     1 3 3 1
     1 4 6 4 1
     1 5 10 10 5 1
     1 6 15 20 15 6 1
     ....
    

    要求:用户输入行数,并打印出杨辉三角形 – 用到了循环嵌套,二维数组

     public static void main(String[] args) {
     	System.out.println("请输入行数:");
     	Scanner scanner = new  Scanner(System.in);
     	int row = scanner.nextInt();
     	int[][] ary = new int[row][row];
     	//打印
     	for(int i=0;i<row;i++) {  //表示行数
     		for(int j=0;j<=i;j++) {  //表示列数
     			if(j==0 || j==i) {
     				ary[i][j] = 1;
     			}else {
     				ary[i][j] = ary[i-1][j]+ary[i-1][j-1];
     			}
     			System.out.print(ary[i][j]+"\t");
     		}
     		System.out.println();
     	}
     	scanner.close();
     }
    

<4>

方法重写:override

  1. 概念:在具有继承关系的父子类中,子类对从父类中继承的某个方法的方法体进行重新实现
  2. 规则:2同2小1大 —面试题笔试题中的选择题
    1. 方法名相同,参数列表相同

    2. 方法返回值类型 子类<=父类

      1. 父类 void 子类 void
        class Super{
        public void test(){…}
        }
        class Sub extends Super{
        public void test(){…}
        }

      2. 父类 基本类型 子类 必须相同

        1. eg:若父类中某方法返回值类型为long,子类对其重写,返回值类型为int,是错误的
      3. 父类 引用类型 子类 是其子类类型,也可以相同的

         前提:class Student extends Person
        
         class Super{
         	public Person test(){....}
         }
         class Sub extends Super{
         	public Student test(){....}
         }
        
    3. 如果父类中某个方法抛出异常,子类重写此方法,抛出的异常<=父类的

    4. 子类重写的方法的访问控制修饰符>=父类中访问控制修饰符

       class Super{
       	void test(){....}   //默认的
       }
       class Sub extends Super(){
       	private void test(){....}
       	//此处为private是错误的,若为其他访问控制修饰符,都正确
       }
      
  3. 方法重载(overload)和方法重写(override)的区别 — 面试题
    1. 分别描述二者
      1. 方法重载是指在同一个类中,存在多个方法名相同,参数列表不同的方法
      2. 方法重写是指在具有继承关系的父子类中,子类对继承自父类的某个方法的方法体进行重新实现
    2. 重载遵循编译期绑定原则,重写遵循运行期绑定原则的

访问控制修饰符:4种

public:修饰的成员可以被所有类访问的
protected:修饰的成员可以被本类访问,可以给同包下的类访问,还可以被不同包下的派生类访问
默认的:修饰的成员可以被本类访问,可以被同包下的其他类访问
private:修饰的成员只能被本类访问

static,final

  1. static和final都是修饰符

  2. final:是一个修饰符:最终的,不变的

    1. 变量:一旦初始化,值不可以改变
      1. 可以是成员变量,也可以是局部变量
    2. 方法:不可被重写
    3. 类:不可以被继承

    eg: final Person per = new Person();
    per是引用,是一个变量,不是对象

  3. static:是一个修饰符:
    static修饰的成员都是属于类的,都是保存在方法区的

    1. 成员变量:
      1. 属于类的,通过类名调用,保存在方法区,在类加载时期进行初始化,只加载一次
    2. 方法:
      1. 属于类的,通过类名调用,保存在方法区
      2. 注意点:static方法体中不能使用this关键字
        1. 原因:调用非static方法时,会隐式的传递一个参数(调用方法的对象),用this接受的, 而调用static方法,通过类名调用的,不是通过对象调用的,所以static方法体中不存在this
    3. 代码块:
      1. 属于类的,保存在方法区,在类加载时期执行,且只执行一次
      2. 通常用于定义静态资源
        1. 静态资源:可以供很多个对象使用的公共的资源,而这些资源通常都是固定不变的
  4. static final可以一起使用:用于修饰常量

    常量命名:所有字母都大写,多个单词之间用_隔开,常量在声明时进行初始化

    注意点:

     public static  final int A = 4;  //建议的
     public final static int A = 4;  //是常量 - 了解
    

static和final —重点,难点,常作为面试题出现

面试题

  1. 以下选项哪个正确(D)

     class Test{
     	public int counter = 0;
    
     	public static void demo(){
     		counter++;  //编译错误
     	}
    
     	public static void main(String[] args){
     		new Test();
     	}
     }
    
     A.0
     B.1
     C.2
     D.编译失败
    
  2. 以下程序的输出结果是: 3 2 1

     class Test{
     	public static int counter = 0;
     	public int a = 0;
     	public Test(){
     		add();
     	}
     	public void add(){
     		Test.counter++;  //1  2  3
     		a++;   //1  2
     	}
    
     	public static void main(String[] args){
     		Test t1 = new Test();
     		t1.a++;
     		Test t2 = new Test();  t2.a = 1
     		Test t3 = new Test();	t3.a = 1
    
     		System.out.println(Test.counter);  3
     		System.out.println(t1.a);  2
     		System.out.println(t2.a);  1
     	}
     }
    
     考点:static的成员变量是属于类的,保存在方法区,这个值的变化和对象是否创建无关
    
  3. 下列代码运行的结果是(D)。

     public class Base { 
         public static final String FOO = "foo"; 
         public static void main(String[] args) { 
             Base b = new Base();
             Sub s = new Sub(); 
             System.out.print(Base.FOO);  //foo
             System.out.print(Sub.FOO);   //bar
             System.out.print(b.FOO); //通过对象访问static成员变量 //foo
             System.out.print(s.FOO);  //bar
             System.out.print(((Base) s).FOO);  //foo
         } 
     } 
     class Sub extends Base { 
         public static final String FOO = "bar";
     }
     A.foofoofoofoofoo
     B.foobarfoobarbar
     C.foobarfoofoofoo
     D.foobarfoobarfoo
    

    注意点:

     访问static资源:
     	1.通过类名访问  -- 推荐使用
     	2.通过对象访问 -- 可以的,但是不推荐使用
    

<5>

抽象:abstract-修饰符

  1. 抽象方法:只有方法的声明,而没有方法体

     eg:public abstract void test();   //是抽象方法
     
     public abstract void demo(){} //不是抽象方法,而是方法体为空
    
     强调:没有方法体和方法体为空是不一样的
    
  2. 抽象类:

    1. 若一个类中有抽象方法,这个类一定是一个抽象类;但是,反之,若一个类是抽象类,这个类中不一定有抽象方法。
    2. 意义:用于提高代码的复用率,提供了一个公共的模板,用于被继承
    3. 注意点:
      1. 若一个子类继承了抽象类(有抽象方法),若子类没有对父类中的所有抽象方法进行重写,那么此时这个子类也成为了抽象类
      2. 抽象类不能实例化的
      3. abstract和final不可以同时修饰一个类

内部类

  1. 成员内部类

    1. 格式:

       public class Outter{
       	private int a = 4;
       	public void test(){
       		//是否能访问到a  --可以
       	}
       	class Inner{
       		int b = 5;
       		public void demo(){
       			System.out.println(this);  //内部类对象
       			System.out.println(Outter.this)  //外部类对象
       		}
       	}
      

      }

    2. 成员内部类通常只服务于外部类的,对外部不具备可见性,所以通常成员内部类的访问控制修饰符都使用private;

      1. 成员内部类可以使用所有的访问控制修饰符
    3. 成员内部类其实是类的成员,可以访问外部类的所有成员,包括私有成员

    4. 注意点:

      1. 在成员内部类中this指向了内部类对象,如果要想在内部类中获取外部类对象,可以通过外部类.this这个引用指向了外部类对象

      2. 若成员内部类的访问控制修饰符是public,外部的其它类如何访问到此内部类对象

         public class Outter{
         	public class Inner{...}
         }
        
         public class Test{
         	public static void main(String[] args){
         		//创建Inner内部类对象,如何创建 --通过外部类对象来调用
         		//Outter out = new Outter();
         		//Inner inner = out.new Inner();
         		等同于:
         		Inner inner = new Outter().new Inner();
         	}
         }
        
  2. 匿名内部类:–使用频率非常高 – 一定要会的

    1. 概念:当某个类的对象只在一个位置使用,那么应该将此类定义为匿名内部类

    2. 前提:

      1. 创建的对象所属的类一定继承了某个父类(可以是抽象类,也可以是普通类),或者是实现了某个接口

      2. 写法:

         public abstract class A{
         		public abstract void demo();
         		public abstract void demo01();
         }
         public class Test{
         	public static void main(String[] args){
         		//创建A类型的对象,这个对象只在这里使用
         		A a = new A(){
         			public void demo(){....}
         		};
         	}
         }
        
    3. 注意点:

      1. 在jdk1.8之前,匿名内部类中若想访问到外面的变量,这个变量只能是final修饰的 – 面试题
        可能出现

面试题

  1. 请问,外部类中的以下哪些可以被成员内部类访问(e)

     A 所有静态变量
     B 所有常量
     C 所有实例变量
     D 只有实例常量
     E 选择A、B、C均正确
    
  2. 以下哪些类的定义是正确的(AB)

     A. public final class A{}
     B. public abstract class A{}
     C. public abstract final class A{}
     D. public static class A{}
    
     	static修饰的三类成员:成员变量,方法,代码块
    
  3. 以下哪些选项是正确的(AD)

     public class Outer{
         public void someOuterMethod(){
             //line 3  //创建成员内部类对象
         }
         public class Inner{}  //属于外部类对象的
         public static void main(String[] args){
             Outer o=new Outer();
             //Line 8
         }
     }
     which instantiates an instance of Inner?
     
     A new Inner();//At Line 3
     B new Inner();//At line 8
     C new Outer.Inner();//At line 8  //正确的写法  new Outer().new Inner()
     D o.new Inner();//At line 8
    
     注意点:成员内部类在外部类中的用法:
     	1. 在外部类的成员变量位置创建
     	2. 在外部类的非static方法中直接创建
     		1. static方法体中能直接访问非static成员吗?
     			1. 不能
     		2. 成员内部类是属于外部类对象的,所以static方法体中应该通过外部类对象才可以访问
     		内部类对象
    
     	结论:static方法体中不能直接访问非static成员,反之,
     	非static方法体中可以访问static成员的,但是不建议这么做
    
     	public class Outer{
     		//成员变量位置创建内部类对象
     		Inner inner = new Inner();
     	
     		public void demo(){
     			//创建内部类对象
     			Inner inner = new Inner();
     		}
     		public class Inner{}
     	}
    

总结:

  1. 抽象

    1. 抽象方法:只有方法声明,没有方法体
      1. 注意没有方法体和方法体为空是不一样的
    2. 抽象类:
      1. 与抽象方法的关系
      2. 注意:
        1. 子类继承抽象类,要么对其中的抽象方法全部重写,要么这个子类也成为抽象类
        2. 抽象类不可以实例化
        3. abstract和final不可以同时修饰一个类
  2. 内部类:

    1. 成员内部类

      1. 注意:
        1. this指向内部类对象,而外部类.this指向外部类对象
        2. 若内部类访问控制修饰符非private,外部可以访问,访问方式:
          1. new Outer().new Inner()
          2. 等同于
            1. Outer out = new Outer();
            2. out.new Inner();
        3. 成员内部类在外部类中的使用:
          1. 在外部类成员变量位置直接new Inner()
          2. 在外部类的非static方法体中直接new Inner()
          3. 注意:若是在static方法中,应通过外部类对象访问
    2. 匿名内部类

      1. 注意:
        1. 前提:创建的匿名内部类要么继承了父类(可以是抽象类,可以是普通类),要么实现了接口
        2. 在JDK1.8之前,匿名内部类要想访问外面的变量,此变量必须是final才可以

<6>

接口

  1. 接口:

    1. 将多个子类中的公共的方法提取出来,若提取的这些方法都是抽象方法,此时就可以将其定义为接口

    2. 将多个子类中的公共的方法提取出来,若提取的这些方法中有普通方法,也有抽象方法,那么此时出现的父类为抽象类

      接口可以说是彻底的抽象

    意义:接口就是一个公共的模板,用于被实现的

  2. 接口的实现:implements

    1. class A implements interface B

扩充知识点:

1. 若实现类没有重写接口中的所有抽象方法,此时这个类就成为了抽象类,这种用法,在java中是经常见得
	意义:
		class A,B  都实现C接口 ,对其中的抽象方法进行重写,
		此时发现,A,B对test方法重写的功能是一样的,
		对demo()重写后的功能是不同的.此时就可以这样来做:

		interface C:  void test();  void demo();
		abstract class D implents C{
			void test(){
				//实现A,B公共的功能
			}
		}

		class A extends D{
			重写demo(){}
		}
		class B extends D{
			重写demo(){}
		}

2. 接口的出现对java中类的单继承的不足作出的弥补

		原因:class A extends B implements C{....}
		若A类还想继承另外一个类,不允许,解决办法:
		将想继承的的内容放到接口中,就可以在继承B的基础上再实现接口
  1. 接口中的成员:2种

    1. 常量

    2. 抽象方法

       接口中为定义的变量提供了默认的修饰符:public static final 
       接口中为定义的方法提供了默认的修饰符:public abstract 
      
  2. 注意点:

    1. 接口是可以多实现的
      1. class A implents B,C,D
    2. 接口的继承可以是多继承的
      1. java中类的继承是单继承的,但是接口的继承是可以多继承的
        1. interface A extends interface B,C,D,E
    3. 接口是不可以实例化的,但是可以作为引用类型使用的
      1. class A implements interface B
        1. B b = new A();
    4. 接口的实现和类的继承是可以混合使用的,但是一定是继承在前,实现在后
      1. class A extends class B implements interface C
  3. 接口和抽象类的区别 – 经常作为面试题出现

    1. 接口中只有常量,抽象类中可以有常量,也可以由变量
    2. 接口中只有抽象方法,抽象类中可以由抽象方法,也可以由普通方法
    3. 都不可以实例化,但是接口是没有构造方法的,抽象类中有构造方法
    4. 抽象类之间的继承只能是单继承,接口之间的继承可以是多继承的

面试题:

	以下哪个选项是正确的(E)
	A. class A extends interface B  //错误的
	B. class A extends class B,class C  //java中类的继承是单继承
	C. interface A extends interface B,class C  //错误的,注意,接口之间的继承是多继承,接口只能继承接口,不能继承类
	D. class A extends class B  interface C //错误,类实现接口而不是继承
	E. interface A extends interface B,interface C

<7>

多态

  1. 什么是多态:Java面向对象的三大特征之一

  2. 为什么/意义:

    1. 相同类型的引用指向不同的对象时,有不同的实现
  3. 如何使用:

    1. 对象造型:
      1. 向上造型:

        1. 通过父类的引用指向子类对象
        2. 注意点:能点什么,看引用的类型
          1. Super a = new Sub();
            a.父类中的成员
      2. 强制造型:

        1. 引用指向的对象,是该类型–向下造型

           //向下造型
           class Sub extends Super
           Super super = new Sub();  //向上造型
           通过super访问不到Sub中特有的成员 --缺点
           Sub su = (Sub)super;   //正确的造型-向下造型
           su.子类中特有的成员
          
        2. 引用指向的对象,实现了该接口或继承了该类

           class C extends class A
           class C implements interface B
          
           A a = new C();  //向上造型
           B b = (B)a;   //正确的 -- 强制造型
          
           class Airplane extends FlyingObject implements Enemy
          
           FlyingObject obj = new Airplane();
           Enemy enemy = (Enemy)obj;   //正确的
          

        题目:

         class A extends C  implements D
         class B extends C
        
         C c = new A();  //向上造型
         A a = (A)c;  //正确的造型  -- 向下造型
         D d = (D)c;  //正确的造型 --强制造型
        
         B b = (B)c;  //错误的造型
        
         总结:强制造型成功与否的关键:看指向的对象类型是否和当前造型成的类型有关
        
      3. 为了避免造型过程中出现类型转换异常,我们一般都要在转换之前进行判断,通过

        1. instanceof
          1. 用法: 引用 instanceof 类型 --boolean

            eg: C c = new A();
            c instanceof D

内存管理

  1. 堆:

    1. 保存的是对象,和实例变量
    2. 当没有任何引用指向此对象时,此时这个对象就成为了垃圾
    3. GC:垃圾回收器
      1. 不定时进行回收
      2. 但是可以通过System.gc()来建议GC尽快回收
    4. 对象的生命周期:
      1. 对象被创建,在堆中存储。之后通过引用可以访问此对象,而当没有任何引用指向此对象时,成为垃圾,等到GC回收
    5. 实例变量的生命周期
      1. 实例变量属于对象的,对象被创建,实例变量存储在堆中,随着对象的销毁而被销毁

    注意点:内存泄漏:使用完的对象一直没有被回收,建议使用完的对象的引用应置为null

  2. 栈:

    1. 保存的是局部变量(参数列表的参数)
    2. 栈帧:
      1. 调用某方法时,为此方法在栈中分配了一块区域,叫做栈帧,该方法内部的局部变量都保存在此栈帧中,随着方法的执行结束,栈帧被销毁
    3. 局部变量的生命周期
      1. 调用方法时局部变量保存在栈帧中,随着方法的执行结束,随着栈帧而销毁
  3. 方法区:

    1. .class字节码文件(方法,static变量)

面试题:

  1. 以下哪个选项是正确的向下造型(B)

     class Sub extends Super
     class Sub1 extends Super
    
     A. Super super = new Super();
     	Sub sub = (Sub)super;   //错误的造型
    
     B.Super super = new Sub();  //向上造型
     	Sub sub = (Sub)super;   //正确的向下造型
    
     C.Super super = new Sub();  //向上造型
     	Sub1 sub = (Sub1)super;  //错误的
    
     D.Sub sub = new Sub();
     	Sub1 sub1 = (Sub1)sub;  //错误的向下造型
    
  2. 以下程序的输出结果是什么()

     class T{
     	public static void main(String[] args){
     		int a = 4;
     		char[] chs = {'a','b','c'};
     		T t = new T();
     		t.change(a,chs);
     		输出 a  ?   //4
     		输出  chs[0]  ?    //g
     	}
    
     	public void change(int a,char[] chs){
     		a = 10;
     		chs[0] = 'g';
     	}
     }
    
  3. 以下程序的输出结果是什么

     class SuperCls{
     	int a = 7;
     	public SuperCls(){
     		test();
     	}
     	public void test(){
     		System.out.println(a);
     	}
     }
     class SubCls extends SuperCls{
     	int a = 8;
     	public SubCls(){
     		test();
     	}
     	public void test(){
     		System.out.println(a);
     	}
     	main:
     		new SubCls();
     }
    
     0  8
    

总结:

  1. 多态
    1. 注意:对象造型–强制造型
  2. 内存管理:
    1. 考点
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值