For the sake of completeness, here is a simple implementation. The concatenation is different to how you intend to implement so as to not spoil the question. What the implementation does is show various usage of Access Modifiers, specifically that a variable declared private can still be accessed from within the Class it was declared, regardless of whether it belongs to the same Object that attempting to access it. This is outlined in the access level table below: 
This shows that a variable declared private is accessibly only within the class it was declared.
As for the purpose of Access Modifiers; they are not explicitly to protect information for "security purposes". They have a role in object oriented programming to encapsulate the implementation; prevent direct access. Remember that with Encapsulation, you are restricting direct access to data while providing methods to allow you to interact with such data. The primary reason I find for Encapsulation is to avoid misuse of a class; For example a user may attempt to adjust the last Node variable to null, which would throw many errors throughout the code below. Getters and Setters are perfectly legitimate ways for allowing various Classes to interact with the data belonging to a Class while still ensuring Encapsulation as you can restrict how a variable can be updated.
public class Queue<Item> {
private Node<Item> first;
private Node<Item> last;
private static class Node<Item> {
private Item item;
private Node<Item> next;
public Node (Item item) {
this.item = item;
}
}
/* Add node to Queue */
public void add (Item item) {
Node<Item> node = new Node(item);
if (last == null) {
this.first = node;
this.last = node;
} else {
last.next = node;
this.last = node;
}
}
/* Static concatenate method */
public static <Item> Queue concatenate (Queue<Item> A, Queue<Item> B) {
Queue<Item> copyA = A.copy();
Queue<Item> copyB = B.copy();
copyA.last.next = copyB.first;
return copyA;
}
/* Copy method to perform a Deep clone */
public Queue<Item> copy() {
Queue<Item> queue = new Queue<>();
Node<Item> iter = first;
while (iter != null) {
queue.add(iter.item);
iter = iter.next;
}
return queue;
}
/* Concatenate method that will modify the item invoking it */
public void concatenateD1(Queue<Item> toAdd) {
Queue<Item> copyToAdd = toAdd.copy();
this.last.next = copyToAdd.first;
this.last = copyToAdd.last;
}
/* Concatenate method that will modify both arrays invoking it */
public void concatenateD2(Queue<Item> toAdd) {
this.last.next = toAdd.first;
this.last = toAdd.last;
}
/* Print method to Test */
public void print() {
Node<Item> iter = first;
while (iter != null) {
System.out.println(iter.item);
iter = iter.next;
}
}
}
This is missing remove and implementation for the Iterable interface as they weren't required for basic implementation. Also note there are three concatenate methods there. The first, concatenate, is a static method that will clone two Queues and concatenate one to the other. Cloning is done to avoid overwriting the original Queues. The second, concatenateD1, is a member method that appends a given Queue to the end of the Queue the method is invoked on. This will only modify the Queue that has invoked the method. The final, concatenateD2, is also a member method that appends the given Queue to the end of the Queue that the method is invoked on. This, however, will modify values from the two Queues in question, thus isn't safe if you want to reused the original Objects.