Java基础知识

1. 面向对象与面向过程的区别

面向过程:

面向过程性能比面向对象高,因为类对象调用需要实例化,开销比较大,比较消耗资源。所以在以性能为主要考察因素时,列如单片机、嵌入式开发、Linux/Unix等一般使用面向过程开发。但是面向过程没有面向对象易维护、易复用、易扩展

面向对象:

面向对象易维护、易复用、易扩展,因为面向对象具有封装、继承、多态的特性,所以可以设计出低耦合的系统,使系统更加灵活,更易于维护。但是面向对象性能比面向过程低。

面向过程性能比面向对象高吗?

Java性能差的主要原因并不是因为它是面向对象语言,而是Java是半编译语言,最终的执行代码并不是可以直接被CPU执行的二进制机械码。
而面向过程语言大多都是直接编译成机械码在电脑上执行,并且其它一些面向过程的脚本语言性能也并不一定比Java好。

2.Java 语言有哪些特点?

  1. 简单易学;
  2. 面向对象(封装、继承、多态);
  3. 平台无关性(JVM具有多个平台版本);
  4. 可靠性;
  5. 安全性;
  6. 支持多线程(C++ 语言没有内置的多线程机制,因此必须调用操作系统的多线程功能来进行多线程程序设计,而 Java 语言却提供了多线程支持);
  7. 支持网络编程并且很方便( Java 语言诞生本身就是为简化网络编程设计的,因此 Java 语言不仅支持网络编程而且很方便);
  8. 编译与解释并存;

3.JDBC简介与使用

JDBC使用七步骤:

1.加载驱动类

静态方法当前数据类型注入DriverManager类中
DriverManager 驱动管理类:管理当前要连接的数据种类的驱动
一般通过反射注入
Class.forName("com.mysql.jdbc.Driver"); //反射

2.获取连接对象 Connection 接口:与当前数据库连接

通过DriverManager类方法 getConnection(url,name,password) 获取连接对象Connection

3.通过连接对象获取执行对象Statement

使用其子接口preparedStatement预处理执行对象
通过Connection类方法prepareStatement(sql)获取预处理执行对象
Statement 接口:执行sql语句并返回结果或执行结果集
preparedStatement 接口:预编译sql,执行sql语句并返回结果或执行结果集
setObject(index,值) 设置sql语句第index个?的值

4.传入sql需要参数,设置sql语句中参数的值

通过preparedStatement 接口方法 setObject(index,值) 设置sql语句第index个?的值

5.执行sql接收返回结果或结果集

preparedStatement 接口方法:
executeUpdata() 执行返回一个结果、
executeQuery() 执行返回一个结果集
使用int类x接收一个结果
使用ResultSetResultSet类rs接收一个结果集

6.分析结果或结果集

一个结果int x ,判断(x>0)即证明sql语句执行成功

一个结果集 ResultSet rs,创建集合List<Object>或List<Map>来存放结果集
while(rs.next()){ //迭代结果集
使用rs.getString("列名")获取结果集该行 列名对应的字符串值
结果集有对应对象时,使用对象,对象属性名对应结果集列名,使用对象set方法将字符串值赋给对象
使用集合List方法add(对象),将对象装入集合list中
结果集没有对应的对象时,使用Map,Map键存列名,值存列名对应的字符串值
使用集合List方法add(map),将map装入集合list中
}

前面六步加异常处理
7.关闭所有资源

先关闭最后开辟的资源,判断时加异常处理
if(null !=rs){rs.close();}
if(null !=pstmt){pstmt.close();}
if(null !=conn){conn.close();}

例子

保存一个Student对象(一个结果)
public void save(Student s)throws Exception{
  String sql="insert into student values(?,?,?,?)";
  Connection conn=null;
  PreparedStatement pstmt=null;
  try{
    //1.加载驱动
    Class.forName("com.mysql.jdbc,Driver"); //反射
    //2.获取连接对象
    conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","root");
    //3.获取预处理执行对象
    pstmt=conn.prepareStatement(sql);
    //4.设置sql参数
    pstmt.setObject(1,s.getS_id() );
    pstmt.setObject(2,s.getS_name() );
    pstmt.setObject(3,s.getS_birth() );
    pstmt.setObject(4,s.getS_sex() );
    //5.接收返回结果
    int x=pstmt.executeUpdata();
    //6.分析结果 一个结果时6可忽略,不用结果分析
    if(x>0){System.out.println("添加成功");}
  }catch(Exception e){
    e.printStackTrace();
  }finally{ //7.关闭
    if(null!=pstmt)try{pstmt.close();}catch(SQLException e){ e.printStackTrace();}
    if(null!=conn)try{conn.close();}catch(SQLException  e){ e.printStackTrace();}
  }
}
查询全部学生对象(一个结果集)
public List<Student> findAll()throws MyDBException{
  List<Student> slist=new ArrayList<Student>();
  String sql="select *from student";
  Connection conn=null;
  PreparedStatement pstmt=null;
  ResultSet rs=null;
  try{
    Class.forName("com.mysql.jdbc.Driver"); //1
    conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","root");  //2
    pstmt=conn.prepareStatement(sql); //3  
    //4
    rs=pstmt.excuteQuery(); //5
    while(rs.next()){ //6
        Student s=new Student();
        s.SetS_id(rs.getString("s_id"));
        s.SetS_name(rs.getString("s_name"));
        s.SetS_birth(rs.getString("s_birth"));
        s.SetS_sex(rs.getString("s_sex"));
        slist.add(s); //加入集合slist中
    }
  }catch(Exception e){
      e.printStackTrace();
  }finally{  //7
    if(null!=rs)try{rs.close();}catch(SQLException e){e.printStackTrace();}
    if(null!=pstmt)try{pstmt.close();}catch(SQLException e){e.printStackTrace();}
    if(null!=conn)try{conn.close();}catch(SQLException e){e.printStackTrace();}
  }
  return slist;
}
联合查询,查询每个学生的信息与成绩总分与平均分集合
public List<Map<String,Object>> findAllMap()throws MyDBException{
  List<Map<String,Object>> slist=new ArrayList<Map<String,Object>>();
  StringBuffer bf=new StringBuffer();
  bf.append("select");
  bf.append("      x.s_id,x.s_name,x.s_sex,");
  bf.append("      sum(x.s_score) zf,avg(x.s_score) pjf");
  bf.append("from(");
  bf.append("      select");
  bf.append("                s.*,");
  bf.append("                 sc.s_score");
  bf.append("       from");
  bf.append("                student s left join score sc on s.s_id=sc.s_id");
  bf.append(")x  group by x.s_id");
  bf.append("      order by sum(x.s_score) desc; ");
  String sql=bf.toString();  
  
  Connection conn=null;
  PreparedStatement pstmt=null;
  ResultSet rs=null;
  try{
     Class.forName("com.mysql.jdbc.Driver"); //1
     conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/test","root","root");//2
     pstmt=conn.prepareStatement(sql);//3 4
     rs=pstmt.executeQuery();//5
     while(rs.next()){ //6
        Map<String,Object> map=new HashMap<String,Object>();
        map.put("s_id",rs.getString("s_id"));
        map.put("s_name",rs.getString("s_name"));
        map.put("s_sex",rs.getString("s_sex"));
        map.put("zf",rs.getDouble("zf"));
        map.put("pjf",rs.getDouble("pjf"));
        slist.add(map);
      }
  }catch(Exception e){
    e.printStackTrace();
  }finally{ //7
    if(null!=rs)try{rs.close();}catch(SQLException e){ e.printStackTrace();}
    if(null!=pstmt)try{pstmt.close();}catch(SQLException e){ e.printStackTrace();}
    if(null!=conn)try{conn.close();}catch(SQLException e){ e.printStackTrace();}
  }
  return slist;
}

4.JVM、JDK、JRE

JVM

java虚拟机(JVM)是运行Java字节码的虚拟机。JVM有针对不同系统的特定实现(Windows,Linux,macOs)目的是使用相同的字节码,它们都会给出相同的结果。

JDK

JDK是Java Development Kit,它是功能齐全的Java SDK(Software Development Kit)。它拥有JRE所拥有的一切,还有编译器(javac)和工具(如javadoc生成api文档和jdb调式程序)。它能够创建和编译程序。

JRE

JRE 是 Java运行时环境。它是运行已编译 Java 程序所需的所有内容的集合,包括 Java虚拟机(JVM),Java类库,java命令和其他的一些基础构件。但是,它不能用于创建新程序。

5. 字符型常量char和字符串常量string的区别?

形式上

字符常量是单引号引起的一个字符; 字符串常量是双引号引起的若干个字符

含义上

字符常量相当于一个整型值( ASCII 值),可以参加表达式运算; 字符串常量代表一个地址值(该字符串在内存中存放位置)

占内存大小

字符常量只占2个字节; 字符串常量占若干个字节(至少一个字符结束标志)

6. 重载和重写的区别

重载overload

发生在同一个类中,方法名必须相同,参数类型不同,个数不同,顺序不同,方法返回值和修饰符可以不同,发生在编译时,例如构造器Constructor的有参构造与无参构造。

重写override

发生在父子类中,子类重写父类方法,方法名,参数列表必须相同,返回值范围小于等于父类,修饰符大于等于父类,如果父类方法私有private,子类不能重写父类方法。例如String类中重写equals()方法hashcode()方法。

7. String StringBuffer 和 StringBuilder 的区别是什么? String 为什么是不可变的?

(1)可变性

String使用final关键字修饰字符数组来储存字符串 private final char value[]; 所以String不可变。

StringBuffer和Stringbuilder都继承AbstractStringBuilder类,AbstractStringBuilder 中也是使用字符数组保存字符串char value[];
没用final,所以可变

StringBuilder 与 StringBuffer 的构造方法都是调用父类构造方法也就是 AbstractStringBuilder 实现的,在API文档中StringBuilder 与 StringBuffer继承Object。

public StringBuilder() {
    super(16);
public StringBuffer () {
    super(16);
AbstractStringBuilder 源码
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    char[] value;
    int count;
    AbstractStringBuilder() {
    }
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

(2)线程安全性

String 中的对象是不可变的,也就可以理解为常量,线程安全
AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作如 append、insert、indexOf 等公共方法。
StringBuffer 对方法加了同步锁synchronized,所以线程安全。
StringBuilder 没对方法加了同步锁,所以线程不安全。

(3)性能

每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象。
StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用
使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险

8.== 与 equals

==:它的作用是判断两个对象的地址是不是相等。

判断两个对象是不是同一个对象(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)。

equals():它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来比较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。
当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

9.hashCode 与 equals

Object类对重写equals方法的要求:

1、自反性:对于任何非空引用x,x.equals(x)应该返回true。

2、对称性:对于任何引用x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true。

3、传递性:对于任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,那么x.equals(z)也应该返回true。

4、一致性:如果x和y引用的对象没有发生变化,那么反复调用x.equals(y)应该返回同样的结果。

5、非空性:对于任意非空引用x,x.equals(null)应该返回false。

hashCode()

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。
在哈希表可以通过哈希码快速找到所需要的对象。

Object类对重写hashCode 方法的要求

1.在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。
 从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
2.如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
3.如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么两个对象不一定必须产生不同的整数结果。
 但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。

10. Collections 工具类和 Arrays 工具类常见方法

Collections 工具类常用方法:

1)排序

void reverse(List list)//反转
void shuffle(List list)//随机排序
void sort(List list)//按自然排序的升序排序
void sort(List list, Comparator c)//定制排序,由Comparator控制排序逻辑
void swap(List list, int i , int j)//交换两个索引位置的元素
void rotate(List list, int distance)
//旋转。当distance为正数时,将list后distance个元素整体移到前面。当distance为负数时,
//将 list的前distance个元素整体移到后面。

2)查找,替换操作

int binarySearch(List list, Object key)//对List进行二分查找,返回索引,注意List必须是有序的
int max(Collection coll)//根据元素的自然顺序,返回最大的元素。 类比int min(Collection coll)
int max(Collection coll, Comparator c)//根据定制排序,返回最大元素,排序规则
    //由Comparatator类控制。类比int min(Collection coll, Comparator c)
void fill(List list, Object obj)//用指定的元素代替指定list中的所有元素。
int frequency(Collection c, Object o)//统计元素出现次数
int indexOfSubList(List list, List target)//统计target在list中第一次出现的索引,
      //找不到则返回-1,类比int lastIndexOfSubList(List source, list target).
boolean replaceAll(List list, Object oldVal, Object newVal)// 用新元素替换旧元素

3)同步控制(不推荐,需要线程安全的集合类型时请考虑使用 JUC 包下的并发集合)

synchronizedCollection(Collection<T>  c) //返回指定 collection 支持的同步(线程安全的)collection。
synchronizedList(List<T> list)//返回指定列表支持的同步(线程安全的)List。
synchronizedMap(Map<K,V> m) //返回由指定映射支持的同步(线程安全的)Map。
synchronizedSet(Set<T> s) //返回指定 set 支持的同步(线程安全的)set。

4)还可以设置不可变集合

参数是原有的集合对象,返回值是该集合的”只读“版本。

emptyXxx(): 返回一个空的、不可变的集合对象,此处的集合既可以是List,也可以是Set,还可以是Map。
singletonXxx(): 返回一个只包含指定对象(只有一个或一个元素)的不可变的集合对象,此处的集合可以是:List,Set,Map。
unmodifiableXxx(): 返回指定集合对象的不可变视图,此处的集合可以是:List,Set,Map。

Arrays类的常见操作

1)排序 : sort()
2)查找 : binarySearch()
3)比较: equals()
4)填充 : fill()
5)转列表: asList()
6)转字符串 : toString()
7)复制: copyOf()

详情见https://gitee.com/SnailClimb/JavaGuide/blob/master/docs/java/Basis/Arrays,CollectionsCommonMethods.md#arrays%E7%B1%BB%E7%9A%84%E5%B8%B8%E8%A7%81%E6%93%8D%E4%BD%9C

11.实现会话跟踪的技术有哪些

1)使用Cookie

向客户端发送Cookie

Cookie c =new Cookie("name","value"); //创建Cookie 
c.setMaxAge(60*60*24); //设置最大时效,此处设置的最大时效为一天
response.addCookie(c); //把Cookie放入到HTTP响应中

从客户端读取Cookie

String name ="name"; 
Cookie[]cookies =request.getCookies(); 
if(cookies !=null){ 
   for(int i= 0;i<cookies.length;i++){ 
    Cookie cookie =cookies[i]; 
    if(name.equals(cookis.getName())) 
    //something is here. 
    //you can get the value 
    cookie.getValue();  
   }
 }

优点: 数据可以持久保存,不需要服务器资源,简单,基于文本的Key-Value
缺点: 大小受到限制,用户可以禁用Cookie功能,由于保存在本地,有一定的安全风险。

2)URL 重写

在URL中添加用户会话的信息作为请求的参数,或者将唯一的会话ID添加到URL结尾以标识一个会话。
优点: 在Cookie被禁用的时候依然可以使用
缺点: 必须对网站的URL进行编码,所有页面必须动态生成,不能用预先记录下来的URL进行访问。

3).隐藏的表单域

<input type="hidden" name ="session" value="..."/>

优点: Cookie被禁时可以使用
缺点: 所有页面必须是表单提交之后的结果。

4)HttpSession

在所有会话跟踪技术中,HttpSession对象是最强大也是功能最多的。当一个用户第一次访问某个网站时会自动创建 HttpSession,每个用户可以访问他自己的HttpSession。可以通过HttpServletRequest对象的getSession方 法获得HttpSession,通过HttpSession的setAttribute方法可以将一个值放在HttpSession中,通过调用 HttpSession对象的getAttribute方法,同时传入属性名就可以获取保存在HttpSession中的对象。
与上面三种方式不同的 是,HttpSession放在服务器的内存中,因此不要将过大的对象放在里面,即使目前的Servlet容器可以在内存将满时将HttpSession 中的对象移到其他存储设备中,但是这样势必影响性能。添加到HttpSession中的值可以是任意Java对象,这个对象最好实现了 Serializable接口,这样Servlet容器在必要的时候可以将其序列化到文件中,否则在序列化时就会出现异常。

Cookie和Session的的区别

Cookie 一般用来保存用户信息

比如①我们在 Cookie 中保存已经登录过得用户信息,下次访问网站的时候页面可以自动帮你登录的一些基本信息给填了;②一般的网站都会有保持登录也就是说下次你再访问网站的时候就不需要重新登录了,这是因为用户登录的时候我们可以存放了一个 Token 在 Cookie 中,下次登录的时候只需要根据 Token 值来查找用户即可(为了安全考虑,重新登录一般要将 Token 重写);③登录一次网站后访问网站其他页面不需要重新登录。

Session 的主要作用就是通过服务端记录用户的状态。

典型的场景是购物车,当你要添加商品到购物车的时候,系统不知道是哪个用户操作的,因为 HTTP 协议是无状态的。服务端给特定的用户创建特定的 Session 之后就可以标识这个用户并且跟踪这个用户了。

Cookie 数据保存在客户端(浏览器端),Session 数据保存在服务器端。相对来说 Session 安全性更高。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335