Java基础整理(校招) 系列一、数据类型和运算符

概述

一些大企业和用人单位对于一个应届毕业生的要求首先是把基础打牢,其次是要求有一定的项目能力,但往往不会要求太高。
笔者在实习的同时,也在为了能去更好更理想的公司做着准备。在我目前的认知里,我更倾向于去一个大公司,我认为长远来看这个选择是最理想的也最为适合我的。笔者在学习做准备的同时,也对自己在大学这些年的学习成果做一个总结。
这些年的学习过程中疏漏了很多基础知识点。所以这个系列的内容,更偏向于java基础方面,有理论知识也有一些对应的面试题,结合起来看效果会更好一些。多数可以找到的面试题也是大同小异,精髓的地方还是要看面试官临场提问。

进入正题

1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制?

可以有多个类,但只能有一个public的类,并且public的类名必须与文件名相一致。

2、switch语句能否作用在byte上,能否作用在long上,能否作用在String上?
在switch(e)中,这里括号中只支持是int,String,enum型的。
  由于java中的类型的自动转型,byte、char、short这三种可以自动转换为int型的类型括号中也支持。
  由于java中包装类的自动拆箱,Integer、Byte、Char、Short这四种类型括号中也支持。
  总结来说:switch()括号中的表达式支持int、String、enum以及可以自动转型为int的其他类型。
  注意:在Java1.6中表达式的类型只能为int和enum,在java1.7后支持了对String的判断

3 、 对于short s1= 1; s1 = s1 + 1;由于s1+1运算时会自动提升表达式的类型,所以结果是int型,再赋值给short类型s1时,编译器将报告需要强制转换类型的错误。
对于short s1= 1; s1 += 1;由于 +=是java语言规定的运算符,java编译器会对它进行特殊处理,会在运算时自动转换类型因此可以正确编译。

4、char型变量中能不能存贮一个中文汉字?为什么?

char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在unicode编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。补充说明:unicode编码占用两个字节,所以,char类型的变量也是占用两个字节。

5、用最有效率的方法算出2乘以8等於几?

2<< 3,(左移三位)因为将一个数左移n位,就相当于乘以了2的n次方,那么,一个数乘以8只要将其左移3位即可,而位运算cpu直接支持的,效率最高,所以,2乘以8等於几的最效率的方法是2<< 3。

6、使用final关键字修饰一个变量时,是引用不能变,还是引用的对象不能变?

使用final关键字修饰一个变量时,是指引用变量不能变,引用变量所指向的对象中的内容还是可以改变的。例如,对于如下语句:
finalStringBuffer a=new StringBuffer(“immutable”);
执行如下语句将报告编译期错误:
a=new StringBuffer("");
但是,执行如下语句则可以通过编译:
a.append(" broken!");
有人在定义方法的参数时,可能想采用如下形式来阻止方法内部修改传进来的参数对象:
public void method(final StringBuffer param){
}
实际上,这是办不到的,在该方法内部仍然可以增加如下代码来修改参数对象:
param.append(“a”);

7、静态变量和实例变量的区别?

在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
例如,对于下面的程序,无论创建多少个实例对象,永远都只分配了一个staticVar变量,并且每创建一个实例对象,这个staticVar就会加1;但是,每创建一个实例对象,就会分配一个instanceVar,即可能分配多个instanceVar,并且每个instanceVar的值都只自加了1次。

public class Demo1 {
    public static int staticVar = 0;

    public int instanceVar = 0;

    public Demo1(){
        staticVar++;
        instanceVar++;
        System.out.println(staticVar +" ://: "+instanceVar);
    }

    public  static  void  main(String[] args){
        for(int i=0;i<10;i++) {
            Demo1 d1 = new Demo1();
        }
    }
}

运行结果如下:

1 ://: 1
2 ://: 1
3 ://: 1
4 ://: 1
5 ://: 1
6 ://: 1
7 ://: 1
8 ://: 1
9 ://: 1
10 ://: 1

8、 数据类型和变量类型
java中分为两种,一种是基本数据类型一共有八个(byte,short,int,long,float,double,char(默认为空),boolean(默认false)),和五种引用数据类型(类、接口类型、数组类型、枚举类型、注解类型)
这里区分一下基本数据类型与引用数据类型的区别:
基本数据类型在被创建时,在栈上给其划分一块内存,将数值直接存储在栈上。
引用数据类型在被创建时,首先要在栈上给其引用(句柄)分配一块内存,而对象的具体信息都存储在堆内存上,然后由栈上面的引用指向堆中对象的地址。
而对于变量类型来说,分为:
类变量(静态变量,当然,也是可以通过ClassName.VariableName的方式访问的):独立于方法之外的变量,用 static 修饰。
实例变量:独立于方法之外的变量,不过没有 static 修饰。(实例变量在对象创建的时候创建,在对象被销毁的时候销毁)
局部变量:类的方法中的变量。(是在栈上分配)

9、关键字
transient:
在说这个关键字之前,我们先要了解一下序列化的概念(将对象转化为字节序列来表示),一般当我们使用缓存cache或者或者远程调用rpc(比如Dubbo)的时候,经常需要让我们实体类实现Serializable接口,目的就是为了让其实现可序列化,当然最后还是应该把序列化的Java对象给反序列化出来。
而这个关键字的作用就是让某些被修饰的成员属性变量不被序列化,当然作用也就是为了节省空间。
volatile:
这个关键字是实现Java内存模型中可见性的,当一个共享变量被volatile修饰时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
synchronized:
造成线程安全问题的主要诱因有两点,一是存在共享数据(也称临界资源),二是存在多条线程共同操作共享数据。因此为了解决这个问题,我们可能需要这样一个方案,当存在多个线程操作共享数据时,需要保证同一时刻有且只有一个线程在操作共享数据,其他线程必须等到该线程处理完数据后再进行,也就出现了 互斥锁,即能达到互斥访问目的的锁,也就是说当一个共享数据被当前正在访问的线程加上互斥锁后,在同一个时刻,其他线程只能处于等待的状态,直到当前线程处理完毕释放该锁。在 Java 中,关键字 synchronized可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作),同时我们还应该注意到synchronized另外一个重要的作用,synchronized可保证一个线程的变化(主要是共享数据的变化)被其他线程所看到(保证可见性,完全可以替代Volatile功能),这点确实也是很重要的。 Volatile见上一条关键字。

synchronized关键字最主要有以下3种应用方式,下面分别介绍
1、修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁
2、修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁 (当synchronized作用于静态方法时,其锁就是当前类的class对象锁。由于静态成员不专属于任何一个实例对象,是类成员,因此通过class对象锁可以控制静态成员的并发操作。)
3、修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象的锁。

Java虚拟机对synchronized的优化
锁的状态总共有四种,无锁状态、偏向锁、轻量级锁和重量级锁。随着锁的竞争,锁可以从偏向锁升级到轻量级锁,再升级到重量级锁,但是锁的升级是单向的,也就是说只能从低到高升级,不会出现锁的降级。

等待唤醒机制与synchronized
等待唤醒机制主要指的是notify/notifyAll和wait方法,在使用这3个方法时,必须处于synchronized代码块或者synchronized方法中,否则就会抛出IllegalMonitorStateException异常,这是因为调用这几个方法前必须拿到当前对象的监视器monitor对象,也就是说notify/notifyAll和wait方法依赖于monitor对象,而synchronized关键字可以获取 monitor ,这也就是为什么notify/notifyAll和wait方法必须在synchronized代码块或者synchronized方法调用的原因。
需要特别理解的一点是,与sleep方法不同的是wait方法调用完成后,线程将被暂停,但wait方法将会释放当前持有的监视器锁(monitor),直到有线程调用notify/notifyAll方法后方能继续执行,而sleep方法只让线程休眠并不释放锁。同时notify/notifyAll方法调用后,并不会马上释放监视器锁,而是在相应的synchronized(){}/synchronized方法执行结束后才自动释放监视器锁。

它的两个缺点
一:由于我们没办法设置synchronized关键字在获取锁的时候等待时间,所以synchronized可能会导致线程为了加锁而无限期地处于阻塞状态。
二:使用synchronized关键字等同于使用了互斥锁,即其他线程都无法获得锁对象的访问权。这种策略对于读多写少的应用而言是很不利的,因为即使多个读者看似可以并发运行,但他们实际上还是串行的,并将最终导致并发性能的下降。

final:
简单说一点,final变量是只读的,不能引用不能重写不能继承,可以用于修饰成员变量、本地变量、方法以及类,当然这里谈一下代码规范,按照Java代码惯例,final变量就是常量,而且通常常量名是要大写的,最后说一下使用final来修饰的好处:

final关键字提高了性能。JVM和Java应用都会缓存final变量。
final变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
使用final关键字,JVM会对方法、变量及类进行优化。

static
非static方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而static方法调用时不需要创建对象,可以直接调用。也就是说,当一个static方法被调用时,可能还没有创建任何实例对象,所以,一个static方法内部无法发出对非static方法的调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值